src/jdk/nashorn/internal/runtime/ScriptObject.java
Print this page
*** 141,150 ****
--- 141,152 ----
static final MethodHandle SETSPILLWITHGROW = findOwnMH("setSpillWithGrow", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, int.class, Object.class, Object.class);
private static final MethodHandle TRUNCATINGFILTER = findOwnMH("truncatingFilter", Object[].class, int.class, Object[].class);
private static final MethodHandle KNOWNFUNCPROPGUARD = findOwnMH("knownFunctionPropertyGuard", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, Object.class, ScriptFunction.class);
+ private static final ArrayList<MethodHandle> protoFilters = new ArrayList<>();
+
/** Method handle for getting a function argument at a given index. Used from MapCreator */
public static final Call GET_ARGUMENT = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getArgument", Object.class, int.class);
/** Method handle for setting a function argument at a given index. Used from MapCreator */
public static final Call SET_ARGUMENT = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArgument", void.class, int.class, Object.class);
*** 1710,1730 ****
// Fold Object(P0, P1, ...) into R(Object, P0, P1, ...) => R(P0, P1, ...)
return getter.replaceMethods(MH.foldArguments(invoker, argDroppingGetter), getter.getGuard());
}
/**
* Find the appropriate GET method for an invoke dynamic call.
*
* @param desc the call site descriptor
* @param request the link request
* @param operator operator for get: getProp, getMethod, getElem etc
*
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
! if (request.isCallSiteUnstable()) {
return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
}
final FindProperty find = findProperty(name, true);
MethodHandle methodHandle;
--- 1712,1770 ----
// Fold Object(P0, P1, ...) into R(Object, P0, P1, ...) => R(P0, P1, ...)
return getter.replaceMethods(MH.foldArguments(invoker, argDroppingGetter), getter.getGuard());
}
/**
+ * Test whether this object contains in its prototype chain or is itself a with-object.
+ * @return true if a with-object was found
+ */
+ final boolean hasWithScope() {
+ if (isScope()) {
+ for (ScriptObject obj = this; obj != null; obj = obj.getProto()) {
+ if (obj instanceof WithObject) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Add a filter to the first argument of {@code methodHandle} that calls its {@link #getProto()} method
+ * {@code depth} times.
+ * @param methodHandle a method handle
+ * @param depth distance to target prototype
+ * @return the filtered method handle
+ */
+ static MethodHandle addProtoFilter(final MethodHandle methodHandle, final int depth) {
+ if (depth == 0) {
+ return methodHandle;
+ }
+ final int listIndex = depth - 1; // We don't need 0-deep walker
+ MethodHandle filter = listIndex < protoFilters.size() ? protoFilters.get(listIndex) : null;
+
+ if(filter == null) {
+ filter = addProtoFilter(GETPROTO, depth - 1);
+ protoFilters.add(null);
+ protoFilters.set(listIndex, filter);
+ }
+
+ return MH.filterArguments(methodHandle, 0, filter.asType(filter.type().changeReturnType(methodHandle.type().parameterType(0))));
+ }
+
+ /**
* Find the appropriate GET method for an invoke dynamic call.
*
* @param desc the call site descriptor
* @param request the link request
* @param operator operator for get: getProp, getMethod, getElem etc
*
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
! if (request.isCallSiteUnstable() || hasWithScope()) {
return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
}
final FindProperty find = findProperty(name, true);
MethodHandle methodHandle;
*** 1746,1771 ****
final Class<?> returnType = desc.getMethodType().returnType();
final Property property = find.getProperty();
methodHandle = find.getGetter(returnType);
// getMap() is fine as we have the prototype switchpoint depending on where the property was found
! final MethodHandle guard = NashornGuards.getMapGuard(getMap());
if (methodHandle != null) {
assert methodHandle.type().returnType().equals(returnType);
if (find.isSelf()) {
! return new GuardedInvocation(methodHandle, ObjectClassGenerator.OBJECT_FIELDS_ONLY &&
! NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType() ? null : guard);
}
! final ScriptObject prototype = find.getOwner();
!
! if (!property.hasGetterFunction(prototype)) {
! methodHandle = bindTo(methodHandle, prototype);
}
! return new GuardedInvocation(methodHandle, getMap().getProtoGetSwitchPoint(proto, name), guard);
}
assert !NashornCallSiteDescriptor.isFastScope(desc);
return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(proto, name), guard);
}
--- 1786,1813 ----
final Class<?> returnType = desc.getMethodType().returnType();
final Property property = find.getProperty();
methodHandle = find.getGetter(returnType);
+ final boolean noGuard = ObjectClassGenerator.OBJECT_FIELDS_ONLY && NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType();
// getMap() is fine as we have the prototype switchpoint depending on where the property was found
! final MethodHandle guard = noGuard ? null : NashornGuards.getMapGuard(getMap());
if (methodHandle != null) {
assert methodHandle.type().returnType().equals(returnType);
if (find.isSelf()) {
! return new GuardedInvocation(methodHandle, guard);
}
! if (!property.hasGetterFunction(find.getOwner())) {
! // If not a scope bind to actual prototype as changing prototype will change the property map.
! // For scopes we install a filter that replaces the self object with the prototype owning the property.
! methodHandle = isScope() ?
! addProtoFilter(methodHandle, find.getProtoChainLength()) :
! bindTo(methodHandle, find.getOwner());
}
! return new GuardedInvocation(methodHandle, noGuard ? null : getMap().getProtoGetSwitchPoint(proto, name), guard);
}
assert !NashornCallSiteDescriptor.isFastScope(desc);
return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(proto, name), guard);
}
*** 1831,1841 ****
*
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
! if (request.isCallSiteUnstable()) {
return findMegaMorphicSetMethod(desc, name);
}
final boolean scope = isScope();
/*
--- 1873,1883 ----
*
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
! if (request.isCallSiteUnstable() || hasWithScope()) {
return findMegaMorphicSetMethod(desc, name);
}
final boolean scope = isScope();
/*
*** 2757,2767 ****
* @param value property value
*/
public final void setObject(final FindProperty find, final boolean strict, final String key, final Object value) {
FindProperty f = find;
! if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) {
f = null;
}
if (f != null) {
if (!f.getProperty().isWritable()) {
--- 2799,2810 ----
* @param value property value
*/
public final void setObject(final FindProperty find, final boolean strict, final String key, final Object value) {
FindProperty f = find;
! if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty) && !isScope()) {
! // Setting a property should not modify the property in prototype unless this is a scope object.
f = null;
}
if (f != null) {
if (!f.getProperty().isWritable()) {