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()) {