8006559: Octane:pdfjs leaks memory, runs slower iteration to iteration
Reviewed-by: attila, sundar, jlaskey
This commit is contained in:
parent
b165a1a882
commit
65661628af
@ -38,7 +38,6 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DE
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE;
|
||||
@ -47,6 +46,8 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIM
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE;
|
||||
@ -238,7 +239,7 @@ public class ConstructorGenerator extends ClassGenerator {
|
||||
mi.loadThis();
|
||||
mi.invokeStatic(PROTOTYPEOBJECT_TYPE, PROTOTYPEOBJECT_SETCONSTRUCTOR,
|
||||
PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC);
|
||||
mi.putField(SCRIPTFUNCTION_TYPE, PROTOTYPE, OBJECT_DESC);
|
||||
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETPROTOTYPE, SCRIPTFUNCTION_SETPROTOTYPE_DESC);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,6 @@ public interface StringConstants {
|
||||
static final Type TYPE_SCRIPTFUNCTIONIMPL = Type.getType(ScriptFunctionImpl.class);
|
||||
static final Type TYPE_SCRIPTOBJECT = Type.getType(ScriptObject.class);
|
||||
|
||||
static final String PROTOTYPE = "prototype";
|
||||
static final String PROTOTYPE_SUFFIX = "$Prototype";
|
||||
static final String CONSTRUCTOR_SUFFIX = "$Constructor";
|
||||
// This field name is known to Nashorn runtime (Context).
|
||||
@ -88,6 +87,8 @@ public interface StringConstants {
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY);
|
||||
static final String SCRIPTFUNCTION_SETARITY = "setArity";
|
||||
static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
|
||||
static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype";
|
||||
static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
|
||||
static final String PROTOTYPEOBJECT_TYPE = TYPE_PROTOTYPEOBJECT.getInternalName();
|
||||
static final String PROTOTYPEOBJECT_SETCONSTRUCTOR = "setConstructor";
|
||||
static final String PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT, TYPE_OBJECT);
|
||||
|
@ -40,7 +40,7 @@ class BoundScriptFunctionImpl extends ScriptFunctionImpl {
|
||||
|
||||
BoundScriptFunctionImpl(ScriptFunctionData data, ScriptFunction targetFunction) {
|
||||
super(data);
|
||||
this.prototype = ScriptRuntime.UNDEFINED;
|
||||
setPrototype(ScriptRuntime.UNDEFINED);
|
||||
this.targetFunction = targetFunction;
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,6 @@ public final class NativeDebug extends ScriptObject {
|
||||
out.println("Scope count " + ScriptObject.getScopeCount());
|
||||
out.println("ScriptObject listeners added " + PropertyListenerManager.getListenersAdded());
|
||||
out.println("ScriptObject listeners removed " + PropertyListenerManager.getListenersRemoved());
|
||||
out.println("ScriptObject listeners dead " + PropertyListenerManager.getListenersDead());
|
||||
out.println("ScriptFunction count " + ScriptObject.getCount());
|
||||
out.println("ScriptFunction invokes " + ScriptFunction.getInvokes());
|
||||
out.println("ScriptFunction allocations " + ScriptFunction.getAllocations());
|
||||
|
@ -42,6 +42,10 @@ import jdk.nashorn.internal.lookup.Lookup;
|
||||
* function objects -- to expose properties like "prototype", "length" etc.
|
||||
*/
|
||||
public class ScriptFunctionImpl extends ScriptFunction {
|
||||
|
||||
/** Reference to constructor prototype. */
|
||||
private Object prototype;
|
||||
|
||||
// property map for strict mode functions
|
||||
private static final PropertyMap strictmodemap$;
|
||||
// property map for bound functions
|
||||
@ -49,6 +53,9 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
// property map for non-strict, non-bound functions.
|
||||
private static final PropertyMap nasgenmap$;
|
||||
|
||||
// Marker object for lazily initialized prototype object
|
||||
private static final Object LAZY_PROTOTYPE = new Object();
|
||||
|
||||
/**
|
||||
* Constructor called by Nasgen generated code, no membercount, use the default map.
|
||||
* Creates builtin functions only.
|
||||
@ -83,8 +90,8 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
* @param methodHandle handle for invocation
|
||||
* @param scope scope object
|
||||
* @param specs specialized versions of this method, if available, null otherwise
|
||||
* @param strict are we in strict mode
|
||||
* @param builtin is this a built-in function
|
||||
* @param isStrict are we in strict mode
|
||||
* @param isBuiltin is this a built-in function
|
||||
* @param isConstructor can the function be used as a constructor (most can; some built-ins are restricted).
|
||||
*/
|
||||
ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
|
||||
@ -235,10 +242,23 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
return Global.objectPrototype();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object getPrototype() {
|
||||
if (prototype == LAZY_PROTOTYPE) {
|
||||
prototype = new PrototypeObject(this);
|
||||
}
|
||||
return prototype;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPrototype(final Object prototype) {
|
||||
this.prototype = prototype;
|
||||
}
|
||||
|
||||
// Internals below..
|
||||
private void init() {
|
||||
this.setProto(Global.instance().getFunctionPrototype());
|
||||
this.setPrototype(new PrototypeObject(this));
|
||||
this.prototype = LAZY_PROTOTYPE;
|
||||
|
||||
if (isStrict()) {
|
||||
final ScriptFunction func = getTypeErrorThrower();
|
||||
|
@ -25,20 +25,20 @@
|
||||
|
||||
package jdk.nashorn.internal.runtime;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Helper class to manage property listeners and notification.
|
||||
*/
|
||||
public class PropertyListenerManager implements PropertyListener {
|
||||
|
||||
/** property listeners for this object. */
|
||||
private Map<PropertyListener,Boolean> listeners;
|
||||
|
||||
// These counters are updated in debug mode
|
||||
private static int listenersAdded;
|
||||
private static int listenersRemoved;
|
||||
private static int listenersDead;
|
||||
|
||||
/**
|
||||
* @return the listenersAdded
|
||||
@ -54,16 +54,6 @@ public class PropertyListenerManager implements PropertyListener {
|
||||
return listenersRemoved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the listenersDead
|
||||
*/
|
||||
public static int getListenersDead() {
|
||||
return listenersDead;
|
||||
}
|
||||
|
||||
/** property listeners for this object. */
|
||||
private List<WeakReference<PropertyListener>> listeners;
|
||||
|
||||
// Property listener management methods
|
||||
|
||||
/**
|
||||
@ -73,12 +63,13 @@ public class PropertyListenerManager implements PropertyListener {
|
||||
*/
|
||||
public final void addPropertyListener(final PropertyListener listener) {
|
||||
if (listeners == null) {
|
||||
listeners = new ArrayList<>();
|
||||
listeners = new WeakHashMap<>();
|
||||
}
|
||||
|
||||
if (Context.DEBUG) {
|
||||
listenersAdded++;
|
||||
}
|
||||
listeners.add(new WeakReference<>(listener));
|
||||
listeners.put(listener, Boolean.TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,15 +79,10 @@ public class PropertyListenerManager implements PropertyListener {
|
||||
*/
|
||||
public final void removePropertyListener(final PropertyListener listener) {
|
||||
if (listeners != null) {
|
||||
final Iterator<WeakReference<PropertyListener>> iter = listeners.iterator();
|
||||
while (iter.hasNext()) {
|
||||
if (iter.next().get() == listener) {
|
||||
if (Context.DEBUG) {
|
||||
listenersRemoved++;
|
||||
}
|
||||
iter.remove();
|
||||
}
|
||||
if (Context.DEBUG) {
|
||||
listenersRemoved++;
|
||||
}
|
||||
listeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,18 +94,8 @@ public class PropertyListenerManager implements PropertyListener {
|
||||
*/
|
||||
protected final void notifyPropertyAdded(final ScriptObject object, final Property prop) {
|
||||
if (listeners != null) {
|
||||
final Iterator<WeakReference<PropertyListener>> iter = listeners.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final WeakReference<PropertyListener> weakRef = iter.next();
|
||||
final PropertyListener listener = weakRef.get();
|
||||
if (listener == null) {
|
||||
if (Context.DEBUG) {
|
||||
listenersDead++;
|
||||
}
|
||||
iter.remove();
|
||||
} else {
|
||||
listener.propertyAdded(object, prop);
|
||||
}
|
||||
for (PropertyListener listener : listeners.keySet()) {
|
||||
listener.propertyAdded(object, prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,18 +108,8 @@ public class PropertyListenerManager implements PropertyListener {
|
||||
*/
|
||||
protected final void notifyPropertyDeleted(final ScriptObject object, final Property prop) {
|
||||
if (listeners != null) {
|
||||
final Iterator<WeakReference<PropertyListener>> iter = listeners.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final WeakReference<PropertyListener> weakRef = iter.next();
|
||||
final PropertyListener listener = weakRef.get();
|
||||
if (listener == null) {
|
||||
if (Context.DEBUG) {
|
||||
listenersDead++;
|
||||
}
|
||||
iter.remove();
|
||||
} else {
|
||||
listener.propertyDeleted(object, prop);
|
||||
}
|
||||
for (PropertyListener listener : listeners.keySet()) {
|
||||
listener.propertyDeleted(object, prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,18 +123,8 @@ public class PropertyListenerManager implements PropertyListener {
|
||||
*/
|
||||
protected final void notifyPropertyModified(final ScriptObject object, final Property oldProp, final Property newProp) {
|
||||
if (listeners != null) {
|
||||
final Iterator<WeakReference<PropertyListener>> iter = listeners.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final WeakReference<PropertyListener> weakRef = iter.next();
|
||||
final PropertyListener listener = weakRef.get();
|
||||
if (listener == null) {
|
||||
if (Context.DEBUG) {
|
||||
listenersDead++;
|
||||
}
|
||||
iter.remove();
|
||||
} else {
|
||||
listener.propertyModified(object, oldProp, newProp);
|
||||
}
|
||||
for (PropertyListener listener : listeners.keySet()) {
|
||||
listener.propertyModified(object, oldProp, newProp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,9 +71,6 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
|
||||
private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
|
||||
|
||||
/** Reference to constructor prototype. */
|
||||
protected Object prototype;
|
||||
|
||||
/** The parent scope. */
|
||||
private final ScriptObject scope;
|
||||
|
||||
@ -221,6 +218,7 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
final ScriptObject object = data.allocate();
|
||||
|
||||
if (object != null) {
|
||||
Object prototype = getPrototype();
|
||||
if (prototype instanceof ScriptObject) {
|
||||
object.setProto((ScriptObject)prototype);
|
||||
}
|
||||
@ -282,24 +280,18 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
* Get the prototype object for this function
|
||||
* @return prototype
|
||||
*/
|
||||
public final Object getPrototype() {
|
||||
return prototype;
|
||||
}
|
||||
public abstract Object getPrototype();
|
||||
|
||||
/**
|
||||
* Set the prototype object for this function
|
||||
* @param prototype new prototype object
|
||||
* @return the prototype parameter
|
||||
*/
|
||||
public final Object setPrototype(final Object prototype) {
|
||||
this.prototype = prototype;
|
||||
return prototype;
|
||||
}
|
||||
public abstract void setPrototype(Object prototype);
|
||||
|
||||
/**
|
||||
* Return the most appropriate invoke handle if there are specializations
|
||||
* @param type most specific method type to look for invocation with
|
||||
* @param callsite args for trampoline invocation
|
||||
* @param args args for trampoline invocation
|
||||
* @return invoke method handle
|
||||
*/
|
||||
private MethodHandle getBestInvoker(final MethodType type, final Object[] args) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user