зеркало из https://github.com/mozilla/gecko-dev.git
In NativeObject.toSource and NativeArray.toStringHelper methods set cx.iterating to null when done to prevent Hashtable with potentially ever growing internal buffers to lay around. Use ObjToIntMap instead of Hashtable for cx.iterating, it servers the same purpose as using JDK 1.2 HashSet, but without breaking 1.1 compatibility.
This commit is contained in:
Родитель
b7296c0a02
Коммит
6bbac51c73
|
@ -2187,7 +2187,8 @@ public class Context {
|
||||||
|
|
||||||
// for Objects, Arrays to tag themselves as being printed out,
|
// for Objects, Arrays to tag themselves as being printed out,
|
||||||
// so they don't print themselves out recursively.
|
// so they don't print themselves out recursively.
|
||||||
Hashtable iterating;
|
// Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility
|
||||||
|
ObjToIntMap iterating;
|
||||||
|
|
||||||
Object interpreterSecurityDomain;
|
Object interpreterSecurityDomain;
|
||||||
|
|
||||||
|
|
|
@ -461,11 +461,7 @@ public class NativeArray extends IdScriptable {
|
||||||
|
|
||||||
long length = (long)getLengthProperty(thisObj);
|
long length = (long)getLengthProperty(thisObj);
|
||||||
|
|
||||||
StringBuffer result = new StringBuffer();
|
StringBuffer result = new StringBuffer(256);
|
||||||
|
|
||||||
if (cx.iterating == null)
|
|
||||||
cx.iterating = new Hashtable(31);
|
|
||||||
boolean iterating = cx.iterating.get(thisObj) == Boolean.TRUE;
|
|
||||||
|
|
||||||
// whether to return '4,unquoted,5' or '[4, "quoted", 5]'
|
// whether to return '4,unquoted,5' or '[4, "quoted", 5]'
|
||||||
String separator;
|
String separator;
|
||||||
|
@ -480,33 +476,40 @@ public class NativeArray extends IdScriptable {
|
||||||
boolean haslast = false;
|
boolean haslast = false;
|
||||||
long i = 0;
|
long i = 0;
|
||||||
|
|
||||||
if (!iterating) {
|
boolean toplevel, iterating;
|
||||||
for (i = 0; i < length; i++) {
|
if (cx.iterating == null) {
|
||||||
if (i > 0) result.append(separator);
|
toplevel = true;
|
||||||
Object elem = getElem(thisObj, i);
|
iterating = false;
|
||||||
if (elem == null || elem == Undefined.instance) {
|
cx.iterating = new ObjToIntMap(31);
|
||||||
haslast = false;
|
}else {
|
||||||
continue;
|
toplevel = false;
|
||||||
}
|
iterating = cx.iterating.has(thisObj);
|
||||||
haslast = true;
|
}
|
||||||
|
|
||||||
if (elem instanceof String) {
|
// Make sure cx.iterating is set to null when done
|
||||||
String s = (String)elem;
|
// so we don't leak memory
|
||||||
if (toSource) {
|
try {
|
||||||
result.append('\"');
|
if (!iterating) {
|
||||||
result.append(ScriptRuntime.escapeString(s));
|
cx.iterating.put(thisObj, 0); // stop recursion.
|
||||||
result.append('\"');
|
for (i = 0; i < length; i++) {
|
||||||
} else {
|
if (i > 0) result.append(separator);
|
||||||
result.append(s);
|
Object elem = getElem(thisObj, i);
|
||||||
|
if (elem == null || elem == Undefined.instance) {
|
||||||
|
haslast = false;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
haslast = true;
|
||||||
/* wrap changes to cx.iterating in a try/finally
|
|
||||||
* so that the reference always gets removed, and
|
if (elem instanceof String) {
|
||||||
* we don't leak memory. Good place for weak
|
String s = (String)elem;
|
||||||
* references, if we had them. */
|
if (toSource) {
|
||||||
try {
|
result.append('\"');
|
||||||
// stop recursion.
|
result.append(ScriptRuntime.escapeString(s));
|
||||||
cx.iterating.put(thisObj, Boolean.TRUE);
|
result.append('\"');
|
||||||
|
} else {
|
||||||
|
result.append(s);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (toLocale && elem != Undefined.instance &&
|
if (toLocale && elem != Undefined.instance &&
|
||||||
elem != null)
|
elem != null)
|
||||||
{
|
{
|
||||||
|
@ -518,11 +521,13 @@ public class NativeArray extends IdScriptable {
|
||||||
ScriptRuntime.emptyArgs);
|
ScriptRuntime.emptyArgs);
|
||||||
}
|
}
|
||||||
result.append(ScriptRuntime.toString(elem));
|
result.append(ScriptRuntime.toString(elem));
|
||||||
} finally {
|
|
||||||
cx.iterating.remove(thisObj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}finally {
|
||||||
|
if (toplevel) {
|
||||||
|
cx.iterating = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toSource) {
|
if (toSource) {
|
||||||
|
|
|
@ -142,48 +142,51 @@ public class NativeObject extends IdScriptable {
|
||||||
|
|
||||||
private static String toSource(Context cx, Scriptable thisObj)
|
private static String toSource(Context cx, Scriptable thisObj)
|
||||||
{
|
{
|
||||||
Scriptable m = thisObj;
|
StringBuffer result = new StringBuffer(256);
|
||||||
|
result.append('{');
|
||||||
|
|
||||||
if (cx.iterating == null)
|
boolean toplevel, iterating;
|
||||||
cx.iterating = new Hashtable(31);
|
if (cx.iterating == null) {
|
||||||
|
toplevel = true;
|
||||||
|
iterating = false;
|
||||||
|
cx.iterating = new ObjToIntMap(31);
|
||||||
|
}else {
|
||||||
|
toplevel = false;
|
||||||
|
iterating = cx.iterating.has(thisObj);
|
||||||
|
}
|
||||||
|
|
||||||
if (cx.iterating.get(m) == Boolean.TRUE) {
|
// Make sure cx.iterating is set to null when done
|
||||||
return "{}"; // stop recursion
|
// so we don't leak memory
|
||||||
} else {
|
try {
|
||||||
StringBuffer result = new StringBuffer("{");
|
if (!iterating) {
|
||||||
Object[] ids = m.getIds();
|
cx.iterating.put(thisObj, 0); // stop recursion.
|
||||||
|
Object[] ids = thisObj.getIds();
|
||||||
for(int i=0; i < ids.length; i++) {
|
for(int i=0; i < ids.length; i++) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
result.append(", ");
|
result.append(", ");
|
||||||
|
Object id = ids[i];
|
||||||
Object id = ids[i];
|
result.append(id);
|
||||||
String idString = ScriptRuntime.toString(id);
|
result.append(':');
|
||||||
Object p = (id instanceof String)
|
Object p = (id instanceof String)
|
||||||
? m.get((String) id, m)
|
? thisObj.get((String) id, thisObj)
|
||||||
: m.get(((Number) id).intValue(), m);
|
: thisObj.get(((Integer) id).intValue(), thisObj);
|
||||||
if (p instanceof String) {
|
if (p instanceof String) {
|
||||||
result.append(idString + ":\""
|
result.append('\"');
|
||||||
+ ScriptRuntime
|
result.append(ScriptRuntime.escapeString((String)p));
|
||||||
.escapeString(ScriptRuntime.toString(p))
|
result.append('\"');
|
||||||
+ "\"");
|
}else {
|
||||||
} else {
|
result.append(ScriptRuntime.toString(p));
|
||||||
/* wrap changes to cx.iterating in a try/finally
|
|
||||||
* so that the reference always gets removed, and
|
|
||||||
* we don't leak memory. Good place for weak
|
|
||||||
* references, if we had them.
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
cx.iterating.put(m, Boolean.TRUE); // stop recursion.
|
|
||||||
result.append(idString + ":" + ScriptRuntime.toString(p));
|
|
||||||
} finally {
|
|
||||||
cx.iterating.remove(m);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.append('}');
|
}finally {
|
||||||
return result.toString();
|
if (toplevel) {
|
||||||
|
cx.iterating = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.append('}');
|
||||||
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object jsFunction_valueOf(Scriptable thisObj) {
|
private static Object jsFunction_valueOf(Scriptable thisObj) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче