mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-24 04:54:40 +02:00
Merge
This commit is contained in:
commit
6891593360
24 changed files with 962 additions and 129 deletions
|
@ -144,6 +144,9 @@ public class DynamicLinker {
|
||||||
private static final String CLASS_NAME = DynamicLinker.class.getName();
|
private static final String CLASS_NAME = DynamicLinker.class.getName();
|
||||||
private static final String RELINK_METHOD_NAME = "relink";
|
private static final String RELINK_METHOD_NAME = "relink";
|
||||||
|
|
||||||
|
private static final String INITIAL_LINK_CLASS_NAME = "java.lang.invoke.MethodHandleNatives";
|
||||||
|
private static final String INITIAL_LINK_METHOD_NAME = "linkCallSite";
|
||||||
|
|
||||||
private final LinkerServices linkerServices;
|
private final LinkerServices linkerServices;
|
||||||
private final int runtimeContextArgCount;
|
private final int runtimeContextArgCount;
|
||||||
private final boolean syncOnRelink;
|
private final boolean syncOnRelink;
|
||||||
|
@ -262,20 +265,54 @@ public class DynamicLinker {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a stack trace element describing the location of the call site currently being relinked on the current
|
* Returns a stack trace element describing the location of the call site currently being linked on the current
|
||||||
* thread. The operation internally creates a Throwable object and inspects its stack trace, so it's potentially
|
* thread. The operation internally creates a Throwable object and inspects its stack trace, so it's potentially
|
||||||
* expensive. The recommended usage for it is in writing diagnostics code.
|
* expensive. The recommended usage for it is in writing diagnostics code.
|
||||||
* @return a stack trace element describing the location of the call site currently being relinked, or null if it is
|
* @return a stack trace element describing the location of the call site currently being linked, or null if it is
|
||||||
* not invoked while a call site is being relinked.
|
* not invoked while a call site is being linked.
|
||||||
*/
|
*/
|
||||||
public static StackTraceElement getRelinkedCallSiteLocation() {
|
public static StackTraceElement getLinkedCallSiteLocation() {
|
||||||
final StackTraceElement[] trace = new Throwable().getStackTrace();
|
final StackTraceElement[] trace = new Throwable().getStackTrace();
|
||||||
for(int i = 0; i < trace.length - 1; ++i) {
|
for(int i = 0; i < trace.length - 1; ++i) {
|
||||||
final StackTraceElement frame = trace[i];
|
final StackTraceElement frame = trace[i];
|
||||||
if(RELINK_METHOD_NAME.equals(frame.getMethodName()) && CLASS_NAME.equals(frame.getClassName())) {
|
if(isRelinkFrame(frame) || isInitialLinkFrame(frame)) {
|
||||||
return trace[i + 1];
|
return trace[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated because of not precise name.
|
||||||
|
* @deprecated Use {@link #getLinkedCallSiteLocation()} instead.
|
||||||
|
* @return see non-deprecated method
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static StackTraceElement getRelinkedCallSiteLocation() {
|
||||||
|
return getLinkedCallSiteLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the frame represents {@code MethodHandleNatives.linkCallSite()}, the frame immediately on top of
|
||||||
|
* the call site frame when the call site is being linked for the first time.
|
||||||
|
* @param frame the frame
|
||||||
|
* @return true if this frame represents {@code MethodHandleNatives.linkCallSite()}
|
||||||
|
*/
|
||||||
|
private static boolean isInitialLinkFrame(final StackTraceElement frame) {
|
||||||
|
return testFrame(frame, INITIAL_LINK_METHOD_NAME, INITIAL_LINK_CLASS_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the frame represents {@code DynamicLinker.relink()}, the frame immediately on top of the call
|
||||||
|
* site frame when the call site is being relinked (linked for second and subsequent times).
|
||||||
|
* @param frame the frame
|
||||||
|
* @return true if this frame represents {@code DynamicLinker.relink()}
|
||||||
|
*/
|
||||||
|
private static boolean isRelinkFrame(final StackTraceElement frame) {
|
||||||
|
return testFrame(frame, RELINK_METHOD_NAME, CLASS_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean testFrame(final StackTraceElement frame, final String methodName, final String className) {
|
||||||
|
return methodName.equals(frame.getMethodName()) && className.equals(frame.getClassName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,8 @@ import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Member;
|
import java.lang.reflect.Member;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -194,6 +196,22 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||||
|
|
||||||
abstract FacetIntrospector createFacetIntrospector();
|
abstract FacetIntrospector createFacetIntrospector();
|
||||||
|
|
||||||
|
Collection<String> getReadablePropertyNames() {
|
||||||
|
return getUnmodifiableKeys(propertyGetters);
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<String> getWritablePropertyNames() {
|
||||||
|
return getUnmodifiableKeys(propertySetters);
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<String> getMethodNames() {
|
||||||
|
return getUnmodifiableKeys(methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Collection<String> getUnmodifiableKeys(Map<String, ?> m) {
|
||||||
|
return Collections.unmodifiableCollection(m.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the specified dynamic method to be the property getter for the specified property. Note that you can only
|
* Sets the specified dynamic method to be the property getter for the specified property. Note that you can only
|
||||||
* use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
|
* use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
|
||||||
|
|
|
@ -84,6 +84,8 @@
|
||||||
package jdk.internal.dynalink.beans;
|
package jdk.internal.dynalink.beans;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||||
import jdk.internal.dynalink.DynamicLinkerFactory;
|
import jdk.internal.dynalink.DynamicLinkerFactory;
|
||||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||||
|
@ -166,6 +168,72 @@ public class BeansLinker implements GuardingDynamicLinker {
|
||||||
return obj instanceof DynamicMethod;
|
return obj instanceof DynamicMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of names of all readable instance properties of a class.
|
||||||
|
* @param clazz the class
|
||||||
|
* @return a collection of names of all readable instance properties of a class.
|
||||||
|
*/
|
||||||
|
public static Collection<String> getReadableInstancePropertyNames(Class<?> clazz) {
|
||||||
|
TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
|
||||||
|
if(linker instanceof BeanLinker) {
|
||||||
|
return ((BeanLinker)linker).getReadablePropertyNames();
|
||||||
|
}
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of names of all writable instance properties of a class.
|
||||||
|
* @param clazz the class
|
||||||
|
* @return a collection of names of all writable instance properties of a class.
|
||||||
|
*/
|
||||||
|
public static Collection<String> getWritableInstancePropertyNames(Class<?> clazz) {
|
||||||
|
TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
|
||||||
|
if(linker instanceof BeanLinker) {
|
||||||
|
return ((BeanLinker)linker).getWritablePropertyNames();
|
||||||
|
}
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of names of all instance methods of a class.
|
||||||
|
* @param clazz the class
|
||||||
|
* @return a collection of names of all instance methods of a class.
|
||||||
|
*/
|
||||||
|
public static Collection<String> getInstanceMethodNames(Class<?> clazz) {
|
||||||
|
TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
|
||||||
|
if(linker instanceof BeanLinker) {
|
||||||
|
return ((BeanLinker)linker).getMethodNames();
|
||||||
|
}
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of names of all readable static properties of a class.
|
||||||
|
* @param clazz the class
|
||||||
|
* @return a collection of names of all readable static properties of a class.
|
||||||
|
*/
|
||||||
|
public static Collection<String> getReadableStaticPropertyNames(Class<?> clazz) {
|
||||||
|
return StaticClassLinker.getReadableStaticPropertyNames(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of names of all writable static properties of a class.
|
||||||
|
* @param clazz the class
|
||||||
|
* @return a collection of names of all writable static properties of a class.
|
||||||
|
*/
|
||||||
|
public static Collection<String> getWritableStaticPropertyNames(Class<?> clazz) {
|
||||||
|
return StaticClassLinker.getWritableStaticPropertyNames(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of names of all static methods of a class.
|
||||||
|
* @param clazz the class
|
||||||
|
* @return a collection of names of all static methods of a class.
|
||||||
|
*/
|
||||||
|
public static Collection<String> getStaticMethodNames(Class<?> clazz) {
|
||||||
|
return StaticClassLinker.getStaticMethodNames(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GuardedInvocation getGuardedInvocation(LinkRequest request, final LinkerServices linkerServices)
|
public GuardedInvocation getGuardedInvocation(LinkRequest request, final LinkerServices linkerServices)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
|
@ -88,10 +88,10 @@ import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||||
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
|
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
|
||||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||||
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.TypeBasedGuardingDynamicLinker;
|
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
|
||||||
|
@ -102,9 +102,9 @@ import jdk.internal.dynalink.support.Lookup;
|
||||||
* @author Attila Szegedi
|
* @author Attila Szegedi
|
||||||
*/
|
*/
|
||||||
class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
|
class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
|
||||||
private final ClassValue<GuardingDynamicLinker> linkers = new ClassValue<GuardingDynamicLinker>() {
|
private static final ClassValue<SingleClassStaticsLinker> linkers = new ClassValue<SingleClassStaticsLinker>() {
|
||||||
@Override
|
@Override
|
||||||
protected GuardingDynamicLinker computeValue(Class<?> clazz) {
|
protected SingleClassStaticsLinker computeValue(Class<?> clazz) {
|
||||||
return new SingleClassStaticsLinker(clazz);
|
return new SingleClassStaticsLinker(clazz);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -160,6 +160,18 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Collection<String> getReadableStaticPropertyNames(Class<?> clazz) {
|
||||||
|
return linkers.get(clazz).getReadablePropertyNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Collection<String> getWritableStaticPropertyNames(Class<?> clazz) {
|
||||||
|
return linkers.get(clazz).getWritablePropertyNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Collection<String> getStaticMethodNames(Class<?> clazz) {
|
||||||
|
return linkers.get(clazz).getMethodNames();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) throws Exception {
|
public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) throws Exception {
|
||||||
final Object receiver = request.getReceiver();
|
final Object receiver = request.getReceiver();
|
||||||
|
|
|
@ -29,8 +29,22 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import jdk.internal.dynalink.beans.BeansLinker;
|
||||||
|
import jdk.internal.dynalink.beans.StaticClass;
|
||||||
|
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||||
|
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
|
||||||
|
import jdk.internal.dynalink.linker.LinkRequest;
|
||||||
|
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
|
||||||
|
import jdk.internal.dynalink.support.LinkRequestImpl;
|
||||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||||
|
import jdk.nashorn.internal.lookup.Lookup;
|
||||||
import jdk.nashorn.internal.objects.annotations.Attribute;
|
import jdk.nashorn.internal.objects.annotations.Attribute;
|
||||||
import jdk.nashorn.internal.objects.annotations.Constructor;
|
import jdk.nashorn.internal.objects.annotations.Constructor;
|
||||||
import jdk.nashorn.internal.objects.annotations.Function;
|
import jdk.nashorn.internal.objects.annotations.Function;
|
||||||
|
@ -58,6 +72,8 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName;
|
||||||
@ScriptClass("Object")
|
@ScriptClass("Object")
|
||||||
public final class NativeObject {
|
public final class NativeObject {
|
||||||
private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
|
private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
|
||||||
|
private static final MethodType MIRROR_GETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class);
|
||||||
|
private static final MethodType MIRROR_SETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class, Object.class);
|
||||||
|
|
||||||
// initialized by nasgen
|
// initialized by nasgen
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -577,14 +593,92 @@ public final class NativeObject {
|
||||||
final AccessorProperty[] props = new AccessorProperty[keys.length];
|
final AccessorProperty[] props = new AccessorProperty[keys.length];
|
||||||
for (int idx = 0; idx < keys.length; idx++) {
|
for (int idx = 0; idx < keys.length; idx++) {
|
||||||
final String name = keys[idx];
|
final String name = keys[idx];
|
||||||
final MethodHandle getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, Object.class, ScriptObjectMirror.class);
|
final MethodHandle getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, MIRROR_GETTER_TYPE);
|
||||||
final MethodHandle setter = Bootstrap.createDynamicInvoker("dyn:setProp|setElem:" + name, Object.class, ScriptObjectMirror.class, Object.class);
|
final MethodHandle setter = Bootstrap.createDynamicInvoker("dyn:setProp|setElem:" + name, MIRROR_SETTER_TYPE);
|
||||||
props[idx] = (AccessorProperty.create(name, 0, getter, setter));
|
props[idx] = (AccessorProperty.create(name, 0, getter, setter));
|
||||||
}
|
}
|
||||||
|
|
||||||
targetObj.addBoundProperties(source, props);
|
targetObj.addBoundProperties(source, props);
|
||||||
|
} else if (source instanceof StaticClass) {
|
||||||
|
final Class<?> clazz = ((StaticClass)source).getRepresentedClass();
|
||||||
|
bindBeanProperties(targetObj, source, BeansLinker.getReadableStaticPropertyNames(clazz),
|
||||||
|
BeansLinker.getWritableStaticPropertyNames(clazz), BeansLinker.getStaticMethodNames(clazz));
|
||||||
|
} else {
|
||||||
|
final Class<?> clazz = source.getClass();
|
||||||
|
bindBeanProperties(targetObj, source, BeansLinker.getReadableInstancePropertyNames(clazz),
|
||||||
|
BeansLinker.getWritableInstancePropertyNames(clazz), BeansLinker.getInstanceMethodNames(clazz));
|
||||||
}
|
}
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void bindBeanProperties(final ScriptObject targetObj, final Object source,
|
||||||
|
final Collection<String> readablePropertyNames, final Collection<String> writablePropertyNames,
|
||||||
|
final Collection<String> methodNames) {
|
||||||
|
final Set<String> propertyNames = new HashSet<>(readablePropertyNames);
|
||||||
|
propertyNames.addAll(writablePropertyNames);
|
||||||
|
|
||||||
|
final Class<?> clazz = source.getClass();
|
||||||
|
Bootstrap.checkReflectionAccess(clazz);
|
||||||
|
|
||||||
|
final MethodType getterType = MethodType.methodType(Object.class, clazz);
|
||||||
|
final MethodType setterType = MethodType.methodType(Object.class, clazz, Object.class);
|
||||||
|
|
||||||
|
final GuardingDynamicLinker linker = BeansLinker.getLinkerForClass(clazz);
|
||||||
|
|
||||||
|
final List<AccessorProperty> properties = new ArrayList<>(propertyNames.size() + methodNames.size());
|
||||||
|
for(final String methodName: methodNames) {
|
||||||
|
properties.add(AccessorProperty.create(methodName, Property.NOT_WRITABLE,
|
||||||
|
getBoundBeanMethodGetter(source, getBeanOperation(linker, "dyn:getMethod:" + methodName, getterType, source)),
|
||||||
|
null));
|
||||||
|
}
|
||||||
|
for(final String propertyName: propertyNames) {
|
||||||
|
final boolean isWritable = writablePropertyNames.contains(propertyName);
|
||||||
|
properties.add(AccessorProperty.create(propertyName, isWritable ? 0 : Property.NOT_WRITABLE,
|
||||||
|
readablePropertyNames.contains(propertyName) ? getBeanOperation(linker, "dyn:getProp:" + propertyName, getterType, source) : Lookup.EMPTY_GETTER,
|
||||||
|
isWritable ? getBeanOperation(linker, "dyn:setProp:" + propertyName, setterType, source) : Lookup.EMPTY_SETTER));
|
||||||
|
}
|
||||||
|
|
||||||
|
targetObj.addBoundProperties(source, properties.toArray(new AccessorProperty[properties.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodHandle getBoundBeanMethodGetter(Object source, MethodHandle methodGetter) {
|
||||||
|
try {
|
||||||
|
// NOTE: we're relying on the fact that "dyn:getMethod:..." return value is constant for any given method
|
||||||
|
// name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is
|
||||||
|
// constant for any given method name and object's class.)
|
||||||
|
return MethodHandles.dropArguments(MethodHandles.constant(Object.class,
|
||||||
|
Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class);
|
||||||
|
} catch(RuntimeException|Error e) {
|
||||||
|
throw e;
|
||||||
|
} catch(Throwable t) {
|
||||||
|
throw new RuntimeException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final String operation,
|
||||||
|
final MethodType methodType, final Object source) {
|
||||||
|
final GuardedInvocation inv;
|
||||||
|
try {
|
||||||
|
inv = linker.getGuardedInvocation(createLinkRequest(operation, methodType, source),
|
||||||
|
Bootstrap.getLinkerServices());
|
||||||
|
assert passesGuard(source, inv.getGuard());
|
||||||
|
} catch(RuntimeException|Error e) {
|
||||||
|
throw e;
|
||||||
|
} catch(Throwable t) {
|
||||||
|
throw new RuntimeException(t);
|
||||||
|
}
|
||||||
|
assert inv.getSwitchPoint() == null; // Linkers in Dynalink's beans package don't use switchpoints.
|
||||||
|
// We discard the guard, as all method handles will be bound to a specific object.
|
||||||
|
return inv.getInvocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean passesGuard(final Object obj, final MethodHandle guard) throws Throwable {
|
||||||
|
return guard == null || (boolean)guard.invoke(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LinkRequest createLinkRequest(String operation, MethodType methodType, Object source) {
|
||||||
|
return new LinkRequestImpl(CallSiteDescriptorFactory.create(MethodHandles.publicLookup(), operation,
|
||||||
|
methodType), false, source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,9 +55,9 @@ import static jdk.nashorn.internal.parser.TokenType.WHILE;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||||
|
@ -1946,14 +1946,14 @@ loop:
|
||||||
|
|
||||||
// Object context.
|
// Object context.
|
||||||
// Prepare to accumulate elements.
|
// Prepare to accumulate elements.
|
||||||
// final List<Node> elements = new ArrayList<>();
|
final List<PropertyNode> elements = new ArrayList<>();
|
||||||
final Map<String, PropertyNode> map = new LinkedHashMap<>();
|
final Map<String, Integer> map = new HashMap<>();
|
||||||
|
|
||||||
// Create a block for the object literal.
|
// Create a block for the object literal.
|
||||||
boolean commaSeen = true;
|
boolean commaSeen = true;
|
||||||
loop:
|
loop:
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RBRACE:
|
case RBRACE:
|
||||||
next();
|
next();
|
||||||
break loop;
|
break loop;
|
||||||
|
@ -1975,14 +1975,16 @@ loop:
|
||||||
// Get and add the next property.
|
// Get and add the next property.
|
||||||
final PropertyNode property = propertyAssignment();
|
final PropertyNode property = propertyAssignment();
|
||||||
final String key = property.getKeyName();
|
final String key = property.getKeyName();
|
||||||
final PropertyNode existingProperty = map.get(key);
|
final Integer existing = map.get(key);
|
||||||
|
|
||||||
if (existingProperty == null) {
|
if (existing == null) {
|
||||||
map.put(key, property);
|
map.put(key, elements.size());
|
||||||
// elements.add(property);
|
elements.add(property);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final PropertyNode existingProperty = elements.get(existing);
|
||||||
|
|
||||||
// ECMA section 11.1.5 Object Initialiser
|
// ECMA section 11.1.5 Object Initialiser
|
||||||
// point # 4 on property assignment production
|
// point # 4 on property assignment production
|
||||||
final Expression value = property.getValue();
|
final Expression value = property.getValue();
|
||||||
|
@ -1993,12 +1995,9 @@ loop:
|
||||||
final FunctionNode prevGetter = existingProperty.getGetter();
|
final FunctionNode prevGetter = existingProperty.getGetter();
|
||||||
final FunctionNode prevSetter = existingProperty.getSetter();
|
final FunctionNode prevSetter = existingProperty.getSetter();
|
||||||
|
|
||||||
boolean redefinitionOk = true;
|
|
||||||
// ECMA 11.1.5 strict mode restrictions
|
// ECMA 11.1.5 strict mode restrictions
|
||||||
if (isStrictMode) {
|
if (isStrictMode && value != null && prevValue != null) {
|
||||||
if (value != null && prevValue != null) {
|
throw error(AbstractParser.message("property.redefinition", key), property.getToken());
|
||||||
redefinitionOk = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
|
final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
|
||||||
|
@ -2006,49 +2005,33 @@ loop:
|
||||||
|
|
||||||
// data property redefined as accessor property
|
// data property redefined as accessor property
|
||||||
if (prevValue != null && isAccessor) {
|
if (prevValue != null && isAccessor) {
|
||||||
redefinitionOk = false;
|
throw error(AbstractParser.message("property.redefinition", key), property.getToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor property redefined as data
|
// accessor property redefined as data
|
||||||
if (isPrevAccessor && value != null) {
|
if (isPrevAccessor && value != null) {
|
||||||
redefinitionOk = false;
|
throw error(AbstractParser.message("property.redefinition", key), property.getToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAccessor && isPrevAccessor) {
|
if (isAccessor && isPrevAccessor) {
|
||||||
if (getter != null && prevGetter != null ||
|
if (getter != null && prevGetter != null ||
|
||||||
setter != null && prevSetter != null) {
|
setter != null && prevSetter != null) {
|
||||||
redefinitionOk = false;
|
throw error(AbstractParser.message("property.redefinition", key), property.getToken());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!redefinitionOk) {
|
|
||||||
throw error(AbstractParser.message("property.redefinition", key), property.getToken());
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyNode newProperty = existingProperty;
|
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (prevValue == null) {
|
elements.add(property);
|
||||||
map.put(key, newProperty = newProperty.setValue(value));
|
} else if (getter != null) {
|
||||||
} else {
|
elements.set(existing, existingProperty.setGetter(getter));
|
||||||
final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT);
|
} else if (setter != null) {
|
||||||
map.put(key, newProperty = newProperty.setValue(new BinaryNode(propertyToken, prevValue, value)));
|
elements.set(existing, existingProperty.setSetter(setter));
|
||||||
}
|
|
||||||
|
|
||||||
map.put(key, newProperty = newProperty.setGetter(null).setSetter(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getter != null) {
|
|
||||||
map.put(key, newProperty = newProperty.setGetter(getter));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setter != null) {
|
|
||||||
map.put(key, newProperty = newProperty.setSetter(setter));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ObjectNode(objectToken, finish, new ArrayList<>(map.values()));
|
return new ObjectNode(objectToken, finish, elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -75,8 +75,13 @@ public abstract class ArrayData {
|
||||||
* @return ArrayData
|
* @return ArrayData
|
||||||
*/
|
*/
|
||||||
public static ArrayData allocate(final int length) {
|
public static ArrayData allocate(final int length) {
|
||||||
final ArrayData arrayData = new IntArrayData(length);
|
if (length == 0) {
|
||||||
return length == 0 ? arrayData : new DeletedRangeArrayFilter(arrayData, 0, length - 1);
|
return new IntArrayData();
|
||||||
|
} else if (length >= SparseArrayData.MAX_DENSE_LENGTH) {
|
||||||
|
return new SparseArrayData(EMPTY_ARRAY, length);
|
||||||
|
} else {
|
||||||
|
return new DeletedRangeArrayFilter(new IntArrayData(length), 0, length - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -75,7 +75,9 @@ public final class IntArrayData extends ArrayData {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object[] toObjectArray(final int[] array, final int length) {
|
private static Object[] toObjectArray(final int[] array, final int length) {
|
||||||
final Object[] oarray = new Object[length];
|
assert length <= array.length : "length exceeds internal array size";
|
||||||
|
final Object[] oarray = new Object[array.length];
|
||||||
|
|
||||||
for (int index = 0; index < length; index++) {
|
for (int index = 0; index < length; index++) {
|
||||||
oarray[index] = Integer.valueOf(array[index]);
|
oarray[index] = Integer.valueOf(array[index]);
|
||||||
}
|
}
|
||||||
|
@ -83,18 +85,22 @@ public final class IntArrayData extends ArrayData {
|
||||||
return oarray;
|
return oarray;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double[] toDoubleArray(final int[] array) {
|
private static double[] toDoubleArray(final int[] array, final int length) {
|
||||||
|
assert length <= array.length : "length exceeds internal array size";
|
||||||
final double[] darray = new double[array.length];
|
final double[] darray = new double[array.length];
|
||||||
for (int index = 0; index < array.length; index++) {
|
|
||||||
|
for (int index = 0; index < length; index++) {
|
||||||
darray[index] = array[index];
|
darray[index] = array[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
return darray;
|
return darray;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long[] toLongArray(final int[] array) {
|
private static long[] toLongArray(final int[] array, final int length) {
|
||||||
|
assert length <= array.length : "length exceeds internal array size";
|
||||||
final long[] larray = new long[array.length];
|
final long[] larray = new long[array.length];
|
||||||
for (int index = 0; index < array.length; index++) {
|
|
||||||
|
for (int index = 0; index < length; index++) {
|
||||||
larray[index] = array[index];
|
larray[index] = array[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,12 +111,14 @@ public final class IntArrayData extends ArrayData {
|
||||||
public ArrayData convert(final Class<?> type) {
|
public ArrayData convert(final Class<?> type) {
|
||||||
if (type == Integer.class) {
|
if (type == Integer.class) {
|
||||||
return this;
|
return this;
|
||||||
} else if (type == Long.class) {
|
}
|
||||||
return new LongArrayData(IntArrayData.toLongArray(array), (int) length());
|
final int length = (int) length();
|
||||||
|
if (type == Long.class) {
|
||||||
|
return new LongArrayData(IntArrayData.toLongArray(array, length), length);
|
||||||
} else if (type == Double.class) {
|
} else if (type == Double.class) {
|
||||||
return new NumberArrayData(IntArrayData.toDoubleArray(array), (int) length());
|
return new NumberArrayData(IntArrayData.toDoubleArray(array, length), length);
|
||||||
} else {
|
} else {
|
||||||
return new ObjectArrayData(IntArrayData.toObjectArray(array, array.length), (int) length());
|
return new ObjectArrayData(IntArrayData.toObjectArray(array, length), length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,26 +169,13 @@ public final class IntArrayData extends ArrayData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayData set(final int index, final Object value, final boolean strict) {
|
public ArrayData set(final int index, final Object value, final boolean strict) {
|
||||||
try {
|
if (value instanceof Integer) {
|
||||||
final int intValue = ((Integer)value).intValue();
|
return set(index, ((Number)value).intValue(), strict);
|
||||||
array[index] = intValue;
|
} else if (value == ScriptRuntime.UNDEFINED) {
|
||||||
setLength(Math.max(index + 1, length()));
|
return new UndefinedArrayFilter(this).set(index, value, strict);
|
||||||
return this;
|
|
||||||
} catch (final NullPointerException | ClassCastException e) {
|
|
||||||
if (value instanceof Short || value instanceof Byte) {
|
|
||||||
final int intValue = ((Number)value).intValue();
|
|
||||||
array[index] = intValue;
|
|
||||||
setLength(Math.max(index + 1, length()));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == ScriptRuntime.UNDEFINED) {
|
|
||||||
return new UndefinedArrayFilter(this).set(index, value, strict);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArrayData newData = convert(value == null ? Object.class : value.getClass());
|
final ArrayData newData = convert(value == null ? Object.class : value.getClass());
|
||||||
|
|
||||||
return newData.set(index, value, strict);
|
return newData.set(index, value, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,9 @@ final class LongArrayData extends ArrayData {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object[] toObjectArray(final long[] array, final int length) {
|
private static Object[] toObjectArray(final long[] array, final int length) {
|
||||||
final Object[] oarray = new Object[length];
|
assert length <= array.length : "length exceeds internal array size";
|
||||||
|
final Object[] oarray = new Object[array.length];
|
||||||
|
|
||||||
for (int index = 0; index < length; index++) {
|
for (int index = 0; index < length; index++) {
|
||||||
oarray[index] = Long.valueOf(array[index]);
|
oarray[index] = Long.valueOf(array[index]);
|
||||||
}
|
}
|
||||||
|
@ -71,9 +73,11 @@ final class LongArrayData extends ArrayData {
|
||||||
return super.asArrayOfType(componentType);
|
return super.asArrayOfType(componentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double[] toDoubleArray(final long[] array) {
|
private static double[] toDoubleArray(final long[] array, final int length) {
|
||||||
|
assert length <= array.length : "length exceeds internal array size";
|
||||||
final double[] darray = new double[array.length];
|
final double[] darray = new double[array.length];
|
||||||
for (int index = 0; index < array.length; index++) {
|
|
||||||
|
for (int index = 0; index < length; index++) {
|
||||||
darray[index] = array[index];
|
darray[index] = array[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,10 +88,12 @@ final class LongArrayData extends ArrayData {
|
||||||
public ArrayData convert(final Class<?> type) {
|
public ArrayData convert(final Class<?> type) {
|
||||||
if (type == Long.class) {
|
if (type == Long.class) {
|
||||||
return this;
|
return this;
|
||||||
} else if (type == Double.class) {
|
}
|
||||||
return new NumberArrayData(LongArrayData.toDoubleArray(array), (int) length());
|
final int length = (int) length();
|
||||||
|
if (type == Double.class) {
|
||||||
|
return new NumberArrayData(LongArrayData.toDoubleArray(array, length), length);
|
||||||
} else {
|
} else {
|
||||||
return new ObjectArrayData(LongArrayData.toObjectArray(array, array.length), (int) length());
|
return new ObjectArrayData(LongArrayData.toObjectArray(array, length), length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,19 +144,13 @@ final class LongArrayData extends ArrayData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayData set(final int index, final Object value, final boolean strict) {
|
public ArrayData set(final int index, final Object value, final boolean strict) {
|
||||||
try {
|
if (value instanceof Long || value instanceof Integer) {
|
||||||
final long longValue = ((Long)value).longValue();
|
return set(index, ((Number)value).longValue(), strict);
|
||||||
array[index] = longValue;
|
} else if (value == ScriptRuntime.UNDEFINED) {
|
||||||
setLength(Math.max(index + 1, length()));
|
return new UndefinedArrayFilter(this).set(index, value, strict);
|
||||||
return this;
|
|
||||||
} catch (final NullPointerException | ClassCastException e) {
|
|
||||||
if (value == ScriptRuntime.UNDEFINED) {
|
|
||||||
return new UndefinedArrayFilter(this).set(index, value, strict);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArrayData newData = convert(value == null ? Object.class : value.getClass());
|
final ArrayData newData = convert(value == null ? Object.class : value.getClass());
|
||||||
|
|
||||||
return newData.set(index, value, strict);
|
return newData.set(index, value, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,9 @@ final class NumberArrayData extends ArrayData {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object[] toObjectArray(final double[] array, final int length) {
|
private static Object[] toObjectArray(final double[] array, final int length) {
|
||||||
final Object[] oarray = new Object[length];
|
assert length <= array.length : "length exceeds internal array size";
|
||||||
|
final Object[] oarray = new Object[array.length];
|
||||||
|
|
||||||
for (int index = 0; index < length; index++) {
|
for (int index = 0; index < length; index++) {
|
||||||
oarray[index] = Double.valueOf(array[index]);
|
oarray[index] = Double.valueOf(array[index]);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +78,8 @@ final class NumberArrayData extends ArrayData {
|
||||||
@Override
|
@Override
|
||||||
public ArrayData convert(final Class<?> type) {
|
public ArrayData convert(final Class<?> type) {
|
||||||
if (type != Double.class && type != Integer.class && type != Long.class) {
|
if (type != Double.class && type != Integer.class && type != Long.class) {
|
||||||
return new ObjectArrayData(NumberArrayData.toObjectArray(array, array.length), (int) length());
|
final int length = (int) length();
|
||||||
|
return new ObjectArrayData(NumberArrayData.toObjectArray(array, length), length);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -127,16 +130,12 @@ final class NumberArrayData extends ArrayData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayData set(final int index, final Object value, final boolean strict) {
|
public ArrayData set(final int index, final Object value, final boolean strict) {
|
||||||
try {
|
if (value instanceof Double || value instanceof Integer || value instanceof Long) {
|
||||||
final double doubleValue = ((Number)value).doubleValue();
|
return set(index, ((Number)value).doubleValue(), strict);
|
||||||
array[index] = doubleValue;
|
} else if (value == UNDEFINED) {
|
||||||
setLength(Math.max(index + 1, length()));
|
return new UndefinedArrayFilter(this).set(index, value, strict);
|
||||||
return this;
|
|
||||||
} catch (final NullPointerException | ClassCastException e) {
|
|
||||||
if (value == UNDEFINED) {
|
|
||||||
return new UndefinedArrayFilter(this).set(index, value, strict);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArrayData newData = convert(value == null ? Object.class : value.getClass());
|
final ArrayData newData = convert(value == null ? Object.class : value.getClass());
|
||||||
return newData.set(index, value, strict);
|
return newData.set(index, value, strict);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ public final class Bootstrap {
|
||||||
static {
|
static {
|
||||||
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
|
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
|
||||||
factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(),
|
factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(),
|
||||||
new JSObjectLinker(), new ReflectionCheckLinker());
|
new BoundDynamicMethodLinker(), new JSObjectLinker(), new ReflectionCheckLinker());
|
||||||
factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker());
|
factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker());
|
||||||
factory.setSyncOnRelink(true);
|
factory.setSyncOnRelink(true);
|
||||||
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
|
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
|
||||||
|
@ -207,6 +207,27 @@ public final class Bootstrap {
|
||||||
return bootstrap(MethodHandles.publicLookup(), opDesc, type, 0).dynamicInvoker();
|
return bootstrap(MethodHandles.publicLookup(), opDesc, type, 0).dynamicInvoker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a bean dynamic method (returned by invoking {@code dyn:getMethod} on an object linked with
|
||||||
|
* {@code BeansLinker} to a receiver.
|
||||||
|
* @param dynamicMethod the dynamic method to bind
|
||||||
|
* @param boundThis the bound "this" value.
|
||||||
|
* @return a bound dynamic method.
|
||||||
|
*/
|
||||||
|
public static Object bindDynamicMethod(Object dynamicMethod, Object boundThis) {
|
||||||
|
return new BoundDynamicMethod(dynamicMethod, boundThis);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the given class is a reflection-specific class (anything in {@code java.lang.reflect} and
|
||||||
|
* {@code java.lang.invoke} package, as well a {@link Class} and any subclass of {@link ClassLoader}) and there is
|
||||||
|
* a security manager in the system, then it checks the {@code nashorn.JavaReflection} {@code RuntimePermission}.
|
||||||
|
* @param clazz the class being tested
|
||||||
|
*/
|
||||||
|
public static void checkReflectionAccess(Class<?> clazz) {
|
||||||
|
ReflectionCheckLinker.checkReflectionAccess(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Nashorn's internally used dynamic linker's services object. Note that in code that is processing a
|
* Returns the Nashorn's internally used dynamic linker's services object. Note that in code that is processing a
|
||||||
* linking request, you will normally use the {@code LinkerServices} object passed by whatever top-level linker
|
* linking request, you will normally use the {@code LinkerServices} object passed by whatever top-level linker
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.nashorn.internal.runtime.linker;
|
||||||
|
|
||||||
|
import jdk.internal.dynalink.beans.BeansLinker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a Dynalink dynamic method bound to a receiver. Note that objects of this class are just the tuples of
|
||||||
|
* a method and a bound this, without any behavior. All the behavior is defined in the {@link BoundDynamicMethodLinker}.
|
||||||
|
*/
|
||||||
|
final class BoundDynamicMethod {
|
||||||
|
private final Object dynamicMethod;
|
||||||
|
private final Object boundThis;
|
||||||
|
|
||||||
|
BoundDynamicMethod(final Object dynamicMethod, final Object boundThis) {
|
||||||
|
assert BeansLinker.isDynamicMethod(dynamicMethod);
|
||||||
|
this.dynamicMethod = dynamicMethod;
|
||||||
|
this.boundThis = boundThis;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object getDynamicMethod() {
|
||||||
|
return dynamicMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object getBoundThis() {
|
||||||
|
return boundThis;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.nashorn.internal.runtime.linker;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||||
|
import jdk.internal.dynalink.beans.BeansLinker;
|
||||||
|
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||||
|
import jdk.internal.dynalink.linker.LinkRequest;
|
||||||
|
import jdk.internal.dynalink.linker.LinkerServices;
|
||||||
|
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
|
||||||
|
import jdk.internal.dynalink.support.Guards;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Links {@link BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method
|
||||||
|
* (they only respond to "dyn:call"), and modifies the returned invocation to deal with the receiver binding.
|
||||||
|
*/
|
||||||
|
final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
|
||||||
|
@Override
|
||||||
|
public boolean canLinkType(Class<?> type) {
|
||||||
|
return type == BoundDynamicMethod.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) throws Exception {
|
||||||
|
final Object objBoundDynamicMethod = linkRequest.getReceiver();
|
||||||
|
if(!(objBoundDynamicMethod instanceof BoundDynamicMethod)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final BoundDynamicMethod boundDynamicMethod = (BoundDynamicMethod)objBoundDynamicMethod;
|
||||||
|
final Object dynamicMethod = boundDynamicMethod.getDynamicMethod();
|
||||||
|
final Object boundThis = boundDynamicMethod.getBoundThis();
|
||||||
|
|
||||||
|
// Replace arguments (boundDynamicMethod, this, ...) => (dynamicMethod, boundThis, ...) when delegating to
|
||||||
|
// BeansLinker
|
||||||
|
final Object[] args = linkRequest.getArguments();
|
||||||
|
args[0] = dynamicMethod;
|
||||||
|
args[1] = boundThis;
|
||||||
|
|
||||||
|
// Use R(T0, T1, ...) => R(dynamicMethod.class, boundThis.class, ...) call site type when delegating to
|
||||||
|
// BeansLinker.
|
||||||
|
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
|
||||||
|
final MethodType type = descriptor.getMethodType();
|
||||||
|
final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(
|
||||||
|
type.changeParameterType(0, dynamicMethod.getClass()).changeParameterType(1, boundThis.getClass()));
|
||||||
|
|
||||||
|
// Delegate to BeansLinker
|
||||||
|
final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethod.getClass()).getGuardedInvocation(
|
||||||
|
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
|
||||||
|
if(inv == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind (dynamicMethod, boundThis) to the handle
|
||||||
|
final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, dynamicMethod, boundThis);
|
||||||
|
final Class<?> p0Type = type.parameterType(0);
|
||||||
|
// Ignore incoming (boundDynamicMethod, this)
|
||||||
|
final MethodHandle droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1));
|
||||||
|
// Identity guard on boundDynamicMethod object
|
||||||
|
final MethodHandle newGuard = Guards.getIdentityGuard(boundDynamicMethod);
|
||||||
|
|
||||||
|
return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -133,7 +133,7 @@ public class LinkerCallSite extends ChainedCallSite {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getScriptLocation() {
|
private static String getScriptLocation() {
|
||||||
final StackTraceElement caller = DynamicLinker.getRelinkedCallSiteLocation();
|
final StackTraceElement caller = DynamicLinker.getLinkedCallSiteLocation();
|
||||||
return caller == null ? "unknown location" : (caller.getFileName() + ":" + caller.getLineNumber());
|
return caller == null ? "unknown location" : (caller.getFileName() + ":" + caller.getLineNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +317,7 @@ public class LinkerCallSite extends ChainedCallSite {
|
||||||
|
|
||||||
private static final MethodHandle TRACEOBJECT = findOwnMH("traceObject", Object.class, MethodHandle.class, Object[].class);
|
private static final MethodHandle TRACEOBJECT = findOwnMH("traceObject", Object.class, MethodHandle.class, Object[].class);
|
||||||
private static final MethodHandle TRACEVOID = findOwnMH("traceVoid", void.class, MethodHandle.class, Object[].class);
|
private static final MethodHandle TRACEVOID = findOwnMH("traceVoid", void.class, MethodHandle.class, Object[].class);
|
||||||
private static final MethodHandle TRACEMISS = findOwnMH("traceMiss", void.class, Object[].class);
|
private static final MethodHandle TRACEMISS = findOwnMH("traceMiss", void.class, String.class, Object[].class);
|
||||||
|
|
||||||
TracingLinkerCallSite(final NashornCallSiteDescriptor desc) {
|
TracingLinkerCallSite(final NashornCallSiteDescriptor desc) {
|
||||||
super(desc);
|
super(desc);
|
||||||
|
@ -363,7 +363,7 @@ public class LinkerCallSite extends ChainedCallSite {
|
||||||
return relink;
|
return relink;
|
||||||
}
|
}
|
||||||
final MethodType type = relink.type();
|
final MethodType type = relink.type();
|
||||||
return MH.foldArguments(relink, MH.asType(MH.asCollector(MH.bindTo(TRACEMISS, this), Object[].class, type.parameterCount()), type.changeReturnType(void.class)));
|
return MH.foldArguments(relink, MH.asType(MH.asCollector(MH.insertArguments(TRACEMISS, 0, this, "MISS " + getScriptLocation() + " "), Object[].class, type.parameterCount()), type.changeReturnType(void.class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printObject(final PrintWriter out, final Object arg) {
|
private void printObject(final PrintWriter out, final Object arg) {
|
||||||
|
@ -482,8 +482,8 @@ public class LinkerCallSite extends ChainedCallSite {
|
||||||
* @throws Throwable if invocation failes or throws exception/error
|
* @throws Throwable if invocation failes or throws exception/error
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void traceMiss(final Object... args) throws Throwable {
|
public void traceMiss(final String desc, final Object... args) throws Throwable {
|
||||||
tracePrint(Context.getCurrentErr(), "MISS ", args, null);
|
tracePrint(Context.getCurrentErr(), desc, args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||||
|
|
|
@ -40,10 +40,10 @@ import jdk.nashorn.internal.runtime.Context;
|
||||||
final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{
|
final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{
|
||||||
@Override
|
@Override
|
||||||
public boolean canLinkType(final Class<?> type) {
|
public boolean canLinkType(final Class<?> type) {
|
||||||
return canLinkTypeStatic(type);
|
return isReflectionClass(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean canLinkTypeStatic(final Class<?> type) {
|
private static boolean isReflectionClass(final Class<?> type) {
|
||||||
if (type == Class.class || ClassLoader.class.isAssignableFrom(type)) {
|
if (type == Class.class || ClassLoader.class.isAssignableFrom(type)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,19 @@ final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{
|
||||||
@Override
|
@Override
|
||||||
public GuardedInvocation getGuardedInvocation(final LinkRequest origRequest, final LinkerServices linkerServices)
|
public GuardedInvocation getGuardedInvocation(final LinkRequest origRequest, final LinkerServices linkerServices)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
checkLinkRequest(origRequest);
|
||||||
|
// let the next linker deal with actual linking
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkReflectionAccess(Class<?> clazz) {
|
||||||
|
final SecurityManager sm = System.getSecurityManager();
|
||||||
|
if (sm != null && isReflectionClass(clazz)) {
|
||||||
|
checkReflectionPermission(sm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkLinkRequest(final LinkRequest origRequest) {
|
||||||
final SecurityManager sm = System.getSecurityManager();
|
final SecurityManager sm = System.getSecurityManager();
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
final LinkRequest requestWithoutContext = origRequest.withoutRuntimeContext(); // Nashorn has no runtime context
|
final LinkRequest requestWithoutContext = origRequest.withoutRuntimeContext(); // Nashorn has no runtime context
|
||||||
|
@ -61,23 +74,19 @@ final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{
|
||||||
// allow 'static' access on Class objects representing public classes of non-restricted packages
|
// allow 'static' access on Class objects representing public classes of non-restricted packages
|
||||||
if ((self instanceof Class) && Modifier.isPublic(((Class<?>)self).getModifiers())) {
|
if ((self instanceof Class) && Modifier.isPublic(((Class<?>)self).getModifiers())) {
|
||||||
final CallSiteDescriptor desc = requestWithoutContext.getCallSiteDescriptor();
|
final CallSiteDescriptor desc = requestWithoutContext.getCallSiteDescriptor();
|
||||||
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
|
if(CallSiteDescriptorFactory.tokenizeOperators(desc).contains("getProp")) {
|
||||||
// check for 'get' on 'static' property
|
if ("static".equals(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
|
||||||
switch (operator) {
|
Context.checkPackageAccess(((Class)self).getName());
|
||||||
case "getProp":
|
// If "getProp:static" passes package access, allow access.
|
||||||
case "getMethod": {
|
return;
|
||||||
if ("static".equals(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
|
|
||||||
Context.checkPackageAccess(((Class)self).getName());
|
|
||||||
// let bean linker do the actual linking part
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
} // fall through for all other stuff
|
|
||||||
}
|
}
|
||||||
sm.checkPermission(new RuntimePermission("nashorn.JavaReflection"));
|
checkReflectionPermission(sm);
|
||||||
}
|
}
|
||||||
// let the next linker deal with actual linking
|
}
|
||||||
return null;
|
|
||||||
|
private static void checkReflectionPermission(final SecurityManager sm) {
|
||||||
|
sm.checkPermission(new RuntimePermission("nashorn.JavaReflection"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
139
nashorn/test/script/basic/JDK-8020324.js
Normal file
139
nashorn/test/script/basic/JDK-8020324.js
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDK-8020324: Implement Object.bindProperties(target, source) for beans
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
* @run
|
||||||
|
*/
|
||||||
|
|
||||||
|
var PropertyBind = Java.type("jdk.nashorn.test.models.PropertyBind")
|
||||||
|
var bean = new PropertyBind
|
||||||
|
|
||||||
|
var obj1 = {}
|
||||||
|
Object.bindProperties(obj1, bean)
|
||||||
|
|
||||||
|
printBanner("Two-way read-write instance field")
|
||||||
|
printEval("obj1.publicInt = 13")
|
||||||
|
printEval("bean.publicInt")
|
||||||
|
printEval("bean.publicInt = 15")
|
||||||
|
printEval("obj1.publicInt")
|
||||||
|
|
||||||
|
printBanner("Read only public instance field")
|
||||||
|
printEval("obj1.publicFinalInt")
|
||||||
|
printEval("obj1.publicFinalInt = 16")
|
||||||
|
printEval("obj1.publicFinalInt")
|
||||||
|
printEval("bean.publicFinalInt")
|
||||||
|
|
||||||
|
printBanner("Two-way read-write instance property")
|
||||||
|
printEval("obj1.readWrite = 17")
|
||||||
|
printEval("bean.readWrite")
|
||||||
|
printEval("bean.readWrite = 18")
|
||||||
|
printEval("obj1.readWrite")
|
||||||
|
printEval("obj1.getReadWrite()")
|
||||||
|
printEval("obj1.setReadWrite(19)")
|
||||||
|
printEval("obj1.readWrite")
|
||||||
|
printEval("bean.readWrite")
|
||||||
|
|
||||||
|
printBanner("Read only instance property")
|
||||||
|
printEval("obj1.readOnly")
|
||||||
|
printEval("obj1.readOnly = 20")
|
||||||
|
printEval("obj1.readOnly")
|
||||||
|
printEval("obj1.getReadOnly()")
|
||||||
|
printEval("bean.getReadOnly()")
|
||||||
|
|
||||||
|
printBanner("Write only instance property")
|
||||||
|
printEval("obj1.writeOnly = 21")
|
||||||
|
printEval("obj1.writeOnly")
|
||||||
|
printEval("bean.writeOnly")
|
||||||
|
printEval("bean.peekWriteOnly()")
|
||||||
|
|
||||||
|
var obj2 = {}
|
||||||
|
Object.bindProperties(obj2, PropertyBind)
|
||||||
|
|
||||||
|
printBanner("Two-way read-write public static field")
|
||||||
|
printEval("obj2.publicStaticInt = 22")
|
||||||
|
printEval("PropertyBind.publicStaticInt")
|
||||||
|
printEval("PropertyBind.publicStaticInt = 23")
|
||||||
|
printEval("obj2.publicStaticInt")
|
||||||
|
|
||||||
|
printBanner("Read only public static field")
|
||||||
|
printEval("obj2.publicStaticFinalInt")
|
||||||
|
printEval("obj2.publicStaticFinalInt = 24")
|
||||||
|
printEval("obj2.publicStaticFinalInt")
|
||||||
|
printEval("PropertyBind.publicStaticFinalInt")
|
||||||
|
|
||||||
|
printBanner("Two-way read-write static property")
|
||||||
|
printEval("obj2.staticReadWrite = 25")
|
||||||
|
printEval("PropertyBind.staticReadWrite")
|
||||||
|
printEval("PropertyBind.staticReadWrite = 26")
|
||||||
|
printEval("obj2.staticReadWrite")
|
||||||
|
printEval("obj2.getStaticReadWrite()")
|
||||||
|
printEval("obj2.setStaticReadWrite(27)")
|
||||||
|
printEval("obj2.staticReadWrite")
|
||||||
|
printEval("PropertyBind.staticReadWrite")
|
||||||
|
|
||||||
|
printBanner("Read only static property")
|
||||||
|
printEval("obj2.staticReadOnly")
|
||||||
|
printEval("obj2.staticReadOnly = 28")
|
||||||
|
printEval("obj2.staticReadOnly")
|
||||||
|
printEval("obj2.getStaticReadOnly()")
|
||||||
|
printEval("PropertyBind.getStaticReadOnly()")
|
||||||
|
|
||||||
|
printBanner("Write only static property")
|
||||||
|
printEval("obj2.staticWriteOnly = 29")
|
||||||
|
printEval("obj2.staticWriteOnly")
|
||||||
|
printEval("PropertyBind.staticWriteOnly")
|
||||||
|
printEval("PropertyBind.peekStaticWriteOnly()")
|
||||||
|
|
||||||
|
printBanner("Sanity check to ensure property values remained what they were")
|
||||||
|
printEval("obj1.publicInt")
|
||||||
|
printEval("bean.publicInt")
|
||||||
|
printEval("obj1.publicFinalInt")
|
||||||
|
printEval("bean.publicFinalInt")
|
||||||
|
printEval("obj1.readWrite")
|
||||||
|
printEval("bean.readWrite")
|
||||||
|
printEval("obj1.readOnly")
|
||||||
|
printEval("bean.readOnly")
|
||||||
|
printEval("bean.peekWriteOnly()")
|
||||||
|
|
||||||
|
printEval("obj2.publicStaticInt")
|
||||||
|
printEval("PropertyBind.publicStaticInt")
|
||||||
|
printEval("obj2.publicStaticFinalInt")
|
||||||
|
printEval("PropertyBind.publicStaticFinalInt")
|
||||||
|
printEval("obj2.staticReadWrite")
|
||||||
|
printEval("PropertyBind.staticReadWrite")
|
||||||
|
printEval("obj2.staticReadOnly")
|
||||||
|
printEval("PropertyBind.staticReadOnly")
|
||||||
|
printEval("PropertyBind.peekStaticWriteOnly()")
|
||||||
|
|
||||||
|
|
||||||
|
function printEval(s) {
|
||||||
|
print(s + ": " + eval(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
function printBanner(s) {
|
||||||
|
print()
|
||||||
|
print("==== " + s + " ====")
|
||||||
|
}
|
90
nashorn/test/script/basic/JDK-8020324.js.EXPECTED
Normal file
90
nashorn/test/script/basic/JDK-8020324.js.EXPECTED
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
|
||||||
|
==== Two-way read-write instance field ====
|
||||||
|
obj1.publicInt = 13: 13
|
||||||
|
bean.publicInt: 13
|
||||||
|
bean.publicInt = 15: 15
|
||||||
|
obj1.publicInt: 15
|
||||||
|
|
||||||
|
==== Read only public instance field ====
|
||||||
|
obj1.publicFinalInt: 42
|
||||||
|
obj1.publicFinalInt = 16: 16
|
||||||
|
obj1.publicFinalInt: 42
|
||||||
|
bean.publicFinalInt: 42
|
||||||
|
|
||||||
|
==== Two-way read-write instance property ====
|
||||||
|
obj1.readWrite = 17: 17
|
||||||
|
bean.readWrite: 17
|
||||||
|
bean.readWrite = 18: 18
|
||||||
|
obj1.readWrite: 18
|
||||||
|
obj1.getReadWrite(): 18
|
||||||
|
obj1.setReadWrite(19): null
|
||||||
|
obj1.readWrite: 19
|
||||||
|
bean.readWrite: 19
|
||||||
|
|
||||||
|
==== Read only instance property ====
|
||||||
|
obj1.readOnly: 123
|
||||||
|
obj1.readOnly = 20: 20
|
||||||
|
obj1.readOnly: 123
|
||||||
|
obj1.getReadOnly(): 123
|
||||||
|
bean.getReadOnly(): 123
|
||||||
|
|
||||||
|
==== Write only instance property ====
|
||||||
|
obj1.writeOnly = 21: 21
|
||||||
|
obj1.writeOnly: undefined
|
||||||
|
bean.writeOnly: undefined
|
||||||
|
bean.peekWriteOnly(): 21
|
||||||
|
|
||||||
|
==== Two-way read-write public static field ====
|
||||||
|
obj2.publicStaticInt = 22: 22
|
||||||
|
PropertyBind.publicStaticInt: 22
|
||||||
|
PropertyBind.publicStaticInt = 23: 23
|
||||||
|
obj2.publicStaticInt: 23
|
||||||
|
|
||||||
|
==== Read only public static field ====
|
||||||
|
obj2.publicStaticFinalInt: 2112
|
||||||
|
obj2.publicStaticFinalInt = 24: 24
|
||||||
|
obj2.publicStaticFinalInt: 2112
|
||||||
|
PropertyBind.publicStaticFinalInt: 2112
|
||||||
|
|
||||||
|
==== Two-way read-write static property ====
|
||||||
|
obj2.staticReadWrite = 25: 25
|
||||||
|
PropertyBind.staticReadWrite: 25
|
||||||
|
PropertyBind.staticReadWrite = 26: 26
|
||||||
|
obj2.staticReadWrite: 26
|
||||||
|
obj2.getStaticReadWrite(): 26
|
||||||
|
obj2.setStaticReadWrite(27): null
|
||||||
|
obj2.staticReadWrite: 27
|
||||||
|
PropertyBind.staticReadWrite: 27
|
||||||
|
|
||||||
|
==== Read only static property ====
|
||||||
|
obj2.staticReadOnly: 1230
|
||||||
|
obj2.staticReadOnly = 28: 28
|
||||||
|
obj2.staticReadOnly: 1230
|
||||||
|
obj2.getStaticReadOnly(): 1230
|
||||||
|
PropertyBind.getStaticReadOnly(): 1230
|
||||||
|
|
||||||
|
==== Write only static property ====
|
||||||
|
obj2.staticWriteOnly = 29: 29
|
||||||
|
obj2.staticWriteOnly: undefined
|
||||||
|
PropertyBind.staticWriteOnly: undefined
|
||||||
|
PropertyBind.peekStaticWriteOnly(): 29
|
||||||
|
|
||||||
|
==== Sanity check to ensure property values remained what they were ====
|
||||||
|
obj1.publicInt: 15
|
||||||
|
bean.publicInt: 15
|
||||||
|
obj1.publicFinalInt: 42
|
||||||
|
bean.publicFinalInt: 42
|
||||||
|
obj1.readWrite: 19
|
||||||
|
bean.readWrite: 19
|
||||||
|
obj1.readOnly: 123
|
||||||
|
bean.readOnly: 123
|
||||||
|
bean.peekWriteOnly(): 21
|
||||||
|
obj2.publicStaticInt: 23
|
||||||
|
PropertyBind.publicStaticInt: 23
|
||||||
|
obj2.publicStaticFinalInt: 2112
|
||||||
|
PropertyBind.publicStaticFinalInt: 2112
|
||||||
|
obj2.staticReadWrite: 27
|
||||||
|
PropertyBind.staticReadWrite: 27
|
||||||
|
obj2.staticReadOnly: 1230
|
||||||
|
PropertyBind.staticReadOnly: 1230
|
||||||
|
PropertyBind.peekStaticWriteOnly(): 29
|
43
nashorn/test/script/basic/JDK-8020354.js
Normal file
43
nashorn/test/script/basic/JDK-8020354.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDK-8020354: Object literal property initialization is not done in source order
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
* @run
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
var obj = ({a: print(1), b: print(2), a: print(3)});
|
||||||
|
|
||||||
|
var obj = ({
|
||||||
|
a: print(1),
|
||||||
|
get x() { print("getting x"); return "x" },
|
||||||
|
set x(v) { print("setting x"); },
|
||||||
|
b: print(2),
|
||||||
|
a: print(3)
|
||||||
|
});
|
||||||
|
|
||||||
|
print(obj.x);
|
||||||
|
obj.x = 4;
|
9
nashorn/test/script/basic/JDK-8020354.js.EXPECTED
Normal file
9
nashorn/test/script/basic/JDK-8020354.js.EXPECTED
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
getting x
|
||||||
|
x
|
||||||
|
setting x
|
43
nashorn/test/script/basic/JDK-8020358.js
Normal file
43
nashorn/test/script/basic/JDK-8020358.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDK-8020358: Array(0xfffffff) throws OutOfMemoryError
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
* @run
|
||||||
|
*/
|
||||||
|
|
||||||
|
var x = new Array(0xfffffff);
|
||||||
|
print(x.length);
|
||||||
|
x[0xffffffe] = 1;
|
||||||
|
print(x.length);
|
||||||
|
x[0xfffffff] = 1;
|
||||||
|
print(x.length);
|
||||||
|
|
||||||
|
x = new Array(0x8ffff);
|
||||||
|
print(x.length);
|
||||||
|
print(Function("return 'ok'").apply(null, x));
|
||||||
|
x[0] = "pass";
|
||||||
|
print(Function("p", "return p").apply(null, x));
|
||||||
|
print(Function("return arguments[0]").apply(null, x));
|
7
nashorn/test/script/basic/JDK-8020358.js.EXPECTED
Normal file
7
nashorn/test/script/basic/JDK-8020358.js.EXPECTED
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
268435455
|
||||||
|
268435455
|
||||||
|
268435456
|
||||||
|
589823
|
||||||
|
ok
|
||||||
|
pass
|
||||||
|
pass
|
37
nashorn/test/script/basic/JDK-8020508.js
Normal file
37
nashorn/test/script/basic/JDK-8020508.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDK-8020508: Enforce reflection check on
|
||||||
|
* Object.bindProperties(target, source) for beans
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
* @run
|
||||||
|
*/
|
||||||
|
|
||||||
|
var x = {}
|
||||||
|
try {
|
||||||
|
Object.bindProperties(x, java.util.Vector.class)
|
||||||
|
} catch(e) {
|
||||||
|
print(e)
|
||||||
|
}
|
1
nashorn/test/script/basic/JDK-8020508.js.EXPECTED
Normal file
1
nashorn/test/script/basic/JDK-8020508.js.EXPECTED
Normal file
|
@ -0,0 +1 @@
|
||||||
|
java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "nashorn.JavaReflection")
|
82
nashorn/test/src/jdk/nashorn/test/models/PropertyBind.java
Normal file
82
nashorn/test/src/jdk/nashorn/test/models/PropertyBind.java
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.nashorn.test.models;
|
||||||
|
|
||||||
|
public class PropertyBind {
|
||||||
|
public static int publicStaticInt;
|
||||||
|
public static final int publicStaticFinalInt = 2112;
|
||||||
|
|
||||||
|
private static int staticReadWrite;
|
||||||
|
private static int staticReadOnly = 1230;
|
||||||
|
private static int staticWriteOnly;
|
||||||
|
|
||||||
|
public int publicInt;
|
||||||
|
public final int publicFinalInt = 42;
|
||||||
|
|
||||||
|
private int readWrite;
|
||||||
|
private int readOnly = 123;
|
||||||
|
private int writeOnly;
|
||||||
|
|
||||||
|
public int getReadWrite() {
|
||||||
|
return readWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReadWrite(int readWrite) {
|
||||||
|
this.readWrite = readWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReadOnly() {
|
||||||
|
return readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWriteOnly(int writeOnly) {
|
||||||
|
this.writeOnly = writeOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int peekWriteOnly() {
|
||||||
|
return writeOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getStaticReadWrite() {
|
||||||
|
return staticReadWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setStaticReadWrite(int staticReadWrite) {
|
||||||
|
PropertyBind.staticReadWrite = staticReadWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getStaticReadOnly() {
|
||||||
|
return staticReadOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setStaticWriteOnly(int staticWriteOnly) {
|
||||||
|
PropertyBind.staticWriteOnly = staticWriteOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int peekStaticWriteOnly() {
|
||||||
|
return PropertyBind.staticWriteOnly;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue