зеркало из https://github.com/mozilla/rhino.git
Remove more obsolete classes: ObjToIntMap and UintMap
These classes can be easily replaced by HashMap and sometimes HashSet without a negative performance impact.
This commit is contained in:
Родитель
03a94c3a69
Коммит
04d54698af
|
@ -11,8 +11,8 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import org.mozilla.javascript.Kit;
|
||||
import org.mozilla.javascript.UintMap;
|
||||
|
||||
/**
|
||||
* ClassFileWriter
|
||||
|
@ -230,7 +230,7 @@ public class ClassFileWriter {
|
|||
short methodNameIndex = itsConstantPool.addUtf8(methodName);
|
||||
short typeIndex = itsConstantPool.addUtf8(type);
|
||||
itsCurrentMethod = new ClassFileMethod(methodName, methodNameIndex, type, typeIndex, flags);
|
||||
itsJumpFroms = new UintMap();
|
||||
itsJumpFroms = new HashMap<>();
|
||||
itsMethods.add(itsCurrentMethod);
|
||||
addSuperBlockStart(0);
|
||||
}
|
||||
|
@ -4347,7 +4347,7 @@ public class ClassFileWriter {
|
|||
// Necessary for generating type information for dead code, which is
|
||||
// expected by the Sun verifier. It is only necessary to store a single
|
||||
// jump source to determine if a block is reachable or not.
|
||||
private UintMap itsJumpFroms = null;
|
||||
private HashMap<Integer, Integer> itsJumpFroms = null;
|
||||
|
||||
private static final int LineNumberTableSize = 16;
|
||||
private static final int ExceptionTableSize = 4;
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
|
||||
package org.mozilla.classfile;
|
||||
|
||||
import org.mozilla.javascript.ObjToIntMap;
|
||||
import org.mozilla.javascript.UintMap;
|
||||
import java.util.HashMap;
|
||||
|
||||
final class ConstantPool {
|
||||
ConstantPool(ClassFileWriter cfw) {
|
||||
|
@ -84,7 +83,7 @@ final class ConstantPool {
|
|||
|
||||
int addConstant(String k) {
|
||||
int utf8Index = 0xFFFF & addUtf8(k);
|
||||
int theIndex = itsStringConstHash.getInt(utf8Index, -1);
|
||||
int theIndex = itsStringConstHash.getOrDefault(utf8Index, -1);
|
||||
if (theIndex == -1) {
|
||||
theIndex = itsTopIndex++;
|
||||
ensure(3);
|
||||
|
@ -156,7 +155,7 @@ final class ConstantPool {
|
|||
}
|
||||
|
||||
short addUtf8(String k) {
|
||||
int theIndex = itsUtf8Hash.get(k, -1);
|
||||
int theIndex = itsUtf8Hash.getOrDefault(k, -1);
|
||||
if (theIndex == -1) {
|
||||
int strLen = k.length();
|
||||
boolean tooBigString;
|
||||
|
@ -223,12 +222,12 @@ final class ConstantPool {
|
|||
}
|
||||
|
||||
short addClass(String className) {
|
||||
int theIndex = itsClassHash.get(className, -1);
|
||||
int theIndex = itsClassHash.getOrDefault(className, -1);
|
||||
if (theIndex == -1) {
|
||||
String slashed = className;
|
||||
if (className.indexOf('.') > 0) {
|
||||
slashed = ClassFileWriter.getSlashedForm(className);
|
||||
theIndex = itsClassHash.get(slashed, -1);
|
||||
theIndex = itsClassHash.getOrDefault(slashed, -1);
|
||||
if (theIndex != -1) {
|
||||
itsClassHash.put(className, theIndex);
|
||||
}
|
||||
|
@ -253,7 +252,7 @@ final class ConstantPool {
|
|||
short addFieldRef(String className, String fieldName, String fieldType) {
|
||||
FieldOrMethodRef ref = new FieldOrMethodRef(className, fieldName, fieldType);
|
||||
|
||||
int theIndex = itsFieldRefHash.get(ref, -1);
|
||||
int theIndex = itsFieldRefHash.getOrDefault(ref, -1);
|
||||
if (theIndex == -1) {
|
||||
short ntIndex = addNameAndType(fieldName, fieldType);
|
||||
short classIndex = addClass(className);
|
||||
|
@ -272,7 +271,7 @@ final class ConstantPool {
|
|||
short addMethodRef(String className, String methodName, String methodType) {
|
||||
FieldOrMethodRef ref = new FieldOrMethodRef(className, methodName, methodType);
|
||||
|
||||
int theIndex = itsMethodRefHash.get(ref, -1);
|
||||
int theIndex = itsMethodRefHash.getOrDefault(ref, -1);
|
||||
if (theIndex == -1) {
|
||||
short ntIndex = addNameAndType(methodName, methodType);
|
||||
short classIndex = addClass(className);
|
||||
|
@ -304,7 +303,7 @@ final class ConstantPool {
|
|||
short addInvokeDynamic(String methodName, String methodType, int bootstrapIndex) {
|
||||
ConstantEntry entry =
|
||||
new ConstantEntry(CONSTANT_InvokeDynamic, bootstrapIndex, methodName, methodType);
|
||||
int theIndex = itsConstantHash.get(entry, -1);
|
||||
int theIndex = itsConstantHash.getOrDefault(entry, -1);
|
||||
|
||||
if (theIndex == -1) {
|
||||
short nameTypeIndex = addNameAndType(methodName, methodType);
|
||||
|
@ -321,7 +320,7 @@ final class ConstantPool {
|
|||
}
|
||||
|
||||
short addMethodHandle(ClassFileWriter.MHandle mh) {
|
||||
int theIndex = itsConstantHash.get(mh, -1);
|
||||
int theIndex = itsConstantHash.getOrDefault(mh, -1);
|
||||
|
||||
if (theIndex == -1) {
|
||||
short ref;
|
||||
|
@ -345,7 +344,7 @@ final class ConstantPool {
|
|||
}
|
||||
|
||||
Object getConstantData(int index) {
|
||||
return itsConstantData.getObject(index);
|
||||
return itsConstantData.get(index);
|
||||
}
|
||||
|
||||
void setConstantData(int index, Object data) {
|
||||
|
@ -353,7 +352,7 @@ final class ConstantPool {
|
|||
}
|
||||
|
||||
byte getConstantType(int index) {
|
||||
return (byte) itsPoolTypes.getInt(index, 0);
|
||||
return itsPoolTypes.getOrDefault(index, (byte) 0);
|
||||
}
|
||||
|
||||
private void ensure(int howMuch) {
|
||||
|
@ -372,16 +371,16 @@ final class ConstantPool {
|
|||
|
||||
private static final int MAX_UTF_ENCODING_SIZE = 65535;
|
||||
|
||||
private UintMap itsStringConstHash = new UintMap();
|
||||
private ObjToIntMap itsUtf8Hash = new ObjToIntMap();
|
||||
private ObjToIntMap itsFieldRefHash = new ObjToIntMap();
|
||||
private ObjToIntMap itsMethodRefHash = new ObjToIntMap();
|
||||
private ObjToIntMap itsClassHash = new ObjToIntMap();
|
||||
private ObjToIntMap itsConstantHash = new ObjToIntMap();
|
||||
private final HashMap<Integer, Integer> itsStringConstHash = new HashMap<>();
|
||||
private final HashMap<String, Integer> itsUtf8Hash = new HashMap<>();
|
||||
private final HashMap<FieldOrMethodRef, Integer> itsFieldRefHash = new HashMap<>();
|
||||
private final HashMap<FieldOrMethodRef, Integer> itsMethodRefHash = new HashMap<>();
|
||||
private final HashMap<String, Integer> itsClassHash = new HashMap<>();
|
||||
private final HashMap<Object, Integer> itsConstantHash = new HashMap<>();
|
||||
|
||||
private int itsTop;
|
||||
private int itsTopIndex;
|
||||
private UintMap itsConstantData = new UintMap();
|
||||
private UintMap itsPoolTypes = new UintMap();
|
||||
private final HashMap<Integer, Object> itsConstantData = new HashMap<>();
|
||||
private final HashMap<Integer, Byte> itsPoolTypes = new HashMap<>();
|
||||
private byte[] itsPool;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ package org.mozilla.javascript;
|
|||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.mozilla.javascript.ast.AstNode;
|
||||
import org.mozilla.javascript.ast.AstRoot;
|
||||
import org.mozilla.javascript.ast.Block;
|
||||
|
@ -39,8 +41,8 @@ class CodeGenerator extends Icode {
|
|||
private int lineNumber;
|
||||
private int doubleTableTop;
|
||||
|
||||
private ObjToIntMap strings = new ObjToIntMap(20);
|
||||
private ObjToIntMap bigInts = new ObjToIntMap(20);
|
||||
private final HashMap<String, Integer> strings = new HashMap<>();
|
||||
private final HashMap<BigInteger, Integer> bigInts = new HashMap<>();
|
||||
private int localTop;
|
||||
private int[] labelTable;
|
||||
private int labelTableTop;
|
||||
|
@ -48,7 +50,7 @@ class CodeGenerator extends Icode {
|
|||
// fixupTable[i] = (label_index << 32) | fixup_site
|
||||
private long[] fixupTable;
|
||||
private int fixupTableTop;
|
||||
private ArrayList<Object> literalIds = new ArrayList<>();
|
||||
private final ArrayList<Object> literalIds = new ArrayList<>();
|
||||
|
||||
private int exceptionTableTop;
|
||||
|
||||
|
@ -147,10 +149,9 @@ class CodeGenerator extends Icode {
|
|||
itsData.itsStringTable = null;
|
||||
} else {
|
||||
itsData.itsStringTable = new String[strings.size()];
|
||||
ObjToIntMap.Iterator iter = strings.newIterator();
|
||||
for (iter.start(); !iter.done(); iter.next()) {
|
||||
String str = (String) iter.getKey();
|
||||
int index = iter.getValue();
|
||||
for (Map.Entry<String, Integer> e : strings.entrySet()) {
|
||||
String str = e.getKey();
|
||||
int index = e.getValue();
|
||||
if (itsData.itsStringTable[index] != null) Kit.codeBug();
|
||||
itsData.itsStringTable[index] = str;
|
||||
}
|
||||
|
@ -166,10 +167,9 @@ class CodeGenerator extends Icode {
|
|||
itsData.itsBigIntTable = null;
|
||||
} else {
|
||||
itsData.itsBigIntTable = new BigInteger[bigInts.size()];
|
||||
ObjToIntMap.Iterator iter = bigInts.newIterator();
|
||||
for (iter.start(); !iter.done(); iter.next()) {
|
||||
BigInteger bigInt = (BigInteger) iter.getKey();
|
||||
int index = iter.getValue();
|
||||
for (Map.Entry<BigInteger, Integer> e : bigInts.entrySet()) {
|
||||
BigInteger bigInt = e.getKey();
|
||||
int index = e.getValue();
|
||||
if (itsData.itsBigIntTable[index] != null) Kit.codeBug();
|
||||
itsData.itsBigIntTable[index] = bigInt;
|
||||
}
|
||||
|
@ -1343,7 +1343,7 @@ class CodeGenerator extends Icode {
|
|||
int offsetSite = fromPC + 1;
|
||||
if (offset != (short) offset) {
|
||||
if (itsData.longJumps == null) {
|
||||
itsData.longJumps = new UintMap();
|
||||
itsData.longJumps = new HashMap<>();
|
||||
}
|
||||
itsData.longJumps.put(offsetSite, jumpPC);
|
||||
offset = 0;
|
||||
|
@ -1469,7 +1469,7 @@ class CodeGenerator extends Icode {
|
|||
}
|
||||
|
||||
private void addStringPrefix(String str) {
|
||||
int index = strings.get(str, -1);
|
||||
int index = strings.getOrDefault(str, -1);
|
||||
if (index == -1) {
|
||||
index = strings.size();
|
||||
strings.put(str, index);
|
||||
|
@ -1489,7 +1489,7 @@ class CodeGenerator extends Icode {
|
|||
}
|
||||
|
||||
private void addBigInt(BigInteger n) {
|
||||
int index = bigInts.get(n, -1);
|
||||
int index = bigInts.getOrDefault(n, -1);
|
||||
if (index == -1) {
|
||||
index = bigInts.size();
|
||||
bigInts.put(n, index);
|
||||
|
|
|
@ -2675,7 +2675,7 @@ public class Context implements Closeable {
|
|||
// for Objects, Arrays to tag themselves as being printed out,
|
||||
// so they don't print themselves out recursively.
|
||||
// Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility
|
||||
ObjToIntMap iterating;
|
||||
Set<Scriptable> iterating;
|
||||
|
||||
Object interpreterSecurityDomain;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.math.BigInteger;
|
|||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.mozilla.javascript.ScriptRuntime.NoSuchMethodShim;
|
||||
|
@ -869,7 +870,7 @@ public final class Interpreter extends Icode implements Evaluator {
|
|||
}
|
||||
|
||||
static int[] getLineNumbers(InterpreterData data) {
|
||||
UintMap presentLines = new UintMap();
|
||||
HashSet<Integer> presentLines = new HashSet<>();
|
||||
|
||||
byte[] iCode = data.itsICode;
|
||||
int iCodeLength = iCode.length;
|
||||
|
@ -879,12 +880,17 @@ public final class Interpreter extends Icode implements Evaluator {
|
|||
if (bytecode == Icode_LINE) {
|
||||
if (span != 3) Kit.codeBug();
|
||||
int line = getIndex(iCode, pc + 1);
|
||||
presentLines.put(line, 0);
|
||||
presentLines.add(line);
|
||||
}
|
||||
pc += span;
|
||||
}
|
||||
|
||||
return presentLines.getKeys();
|
||||
int[] ret = new int[presentLines.size()];
|
||||
int i = 0;
|
||||
for (int num : presentLines) {
|
||||
ret[i++] = num;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2566,7 +2572,7 @@ public final class Interpreter extends Icode implements Evaluator {
|
|||
// -1 accounts for pc pointing to jump opcode + 1
|
||||
frame.pc += offset - 1;
|
||||
} else {
|
||||
frame.pc = frame.idata.longJumps.getExistingInt(frame.pc);
|
||||
frame.pc = frame.idata.longJumps.get(frame.pc);
|
||||
}
|
||||
if (instructionCounting) {
|
||||
frame.pcPrevBranch = frame.pc;
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.mozilla.javascript;
|
|||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import org.mozilla.javascript.debug.DebuggableScript;
|
||||
|
||||
final class InterpreterData implements Serializable, DebuggableScript {
|
||||
|
@ -83,7 +84,7 @@ final class InterpreterData implements Serializable, DebuggableScript {
|
|||
|
||||
Object[] literalIds;
|
||||
|
||||
UintMap longJumps;
|
||||
Map<Integer, Integer> longJumps;
|
||||
|
||||
int firstLinePC = -1; // PC for the first LINE icode
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.security.CodeSource;
|
|||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -33,9 +34,10 @@ public final class JavaAdapter implements IdFunctionCall {
|
|||
static class JavaAdapterSignature {
|
||||
Class<?> superClass;
|
||||
Class<?>[] interfaces;
|
||||
ObjToIntMap names;
|
||||
Map<String, Integer> names;
|
||||
|
||||
JavaAdapterSignature(Class<?> superClass, Class<?>[] interfaces, ObjToIntMap names) {
|
||||
JavaAdapterSignature(
|
||||
Class<?> superClass, Class<?>[] interfaces, Map<String, Integer> names) {
|
||||
this.superClass = superClass;
|
||||
this.interfaces = interfaces;
|
||||
this.names = names;
|
||||
|
@ -52,11 +54,10 @@ public final class JavaAdapter implements IdFunctionCall {
|
|||
if (interfaces[i] != sig.interfaces[i]) return false;
|
||||
}
|
||||
if (names.size() != sig.names.size()) return false;
|
||||
ObjToIntMap.Iterator iter = new ObjToIntMap.Iterator(names);
|
||||
for (iter.start(); !iter.done(); iter.next()) {
|
||||
String name = (String) iter.getKey();
|
||||
int arity = iter.getValue();
|
||||
if (arity != sig.names.get(name, arity + 1)) return false;
|
||||
for (Map.Entry<String, Integer> e : names.entrySet()) {
|
||||
String name = e.getKey();
|
||||
int arity = e.getValue();
|
||||
if (arity != sig.names.getOrDefault(name, arity + 1)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -278,9 +279,9 @@ public final class JavaAdapter implements IdFunctionCall {
|
|||
throw new ClassNotFoundException("adapter");
|
||||
}
|
||||
|
||||
private static ObjToIntMap getObjectFunctionNames(Scriptable obj) {
|
||||
private static Map<String, Integer> getObjectFunctionNames(Scriptable obj) {
|
||||
Object[] ids = ScriptableObject.getPropertyIds(obj);
|
||||
ObjToIntMap map = new ObjToIntMap(ids.length);
|
||||
HashMap<String, Integer> map = new HashMap<>();
|
||||
for (int i = 0; i != ids.length; ++i) {
|
||||
if (!(ids[i] instanceof String)) continue;
|
||||
String id = (String) ids[i];
|
||||
|
@ -302,7 +303,7 @@ public final class JavaAdapter implements IdFunctionCall {
|
|||
ClassCache cache = ClassCache.get(scope);
|
||||
Map<JavaAdapterSignature, Class<?>> generated = cache.getInterfaceAdapterCacheMap();
|
||||
|
||||
ObjToIntMap names = getObjectFunctionNames(obj);
|
||||
Map<String, Integer> names = getObjectFunctionNames(obj);
|
||||
JavaAdapterSignature sig;
|
||||
sig = new JavaAdapterSignature(superClass, interfaces, names);
|
||||
Class<?> adapterClass = generated.get(sig);
|
||||
|
@ -319,7 +320,7 @@ public final class JavaAdapter implements IdFunctionCall {
|
|||
}
|
||||
|
||||
public static byte[] createAdapterCode(
|
||||
ObjToIntMap functionNames,
|
||||
Map<String, Integer> functionNames,
|
||||
String adapterName,
|
||||
Class<?> superClass,
|
||||
Class<?>[] interfaces,
|
||||
|
@ -355,8 +356,8 @@ public final class JavaAdapter implements IdFunctionCall {
|
|||
generateEmptyCtor(cfw, adapterName, superName, scriptClassName);
|
||||
}
|
||||
|
||||
ObjToIntMap generatedOverrides = new ObjToIntMap();
|
||||
ObjToIntMap generatedMethods = new ObjToIntMap();
|
||||
HashMap<String, Integer> generatedOverrides = new HashMap<>();
|
||||
HashMap<String, Integer> generatedMethods = new HashMap<>();
|
||||
|
||||
// generate methods to satisfy all specified interfaces.
|
||||
for (int i = 0; i < interfacesCount; i++) {
|
||||
|
@ -368,7 +369,7 @@ public final class JavaAdapter implements IdFunctionCall {
|
|||
}
|
||||
String methodName = method.getName();
|
||||
Class<?>[] argTypes = method.getParameterTypes();
|
||||
if (!functionNames.has(methodName)) {
|
||||
if (!functionNames.containsKey(methodName)) {
|
||||
try {
|
||||
superClass.getMethod(methodName, argTypes);
|
||||
// The class we're extending implements this method and
|
||||
|
@ -383,7 +384,7 @@ public final class JavaAdapter implements IdFunctionCall {
|
|||
// method/signature.
|
||||
String methodSignature = getMethodSignature(method, argTypes);
|
||||
String methodKey = methodName + methodSignature;
|
||||
if (!generatedOverrides.has(methodKey)) {
|
||||
if (!generatedOverrides.containsKey(methodKey)) {
|
||||
generateMethod(
|
||||
cfw, adapterName, methodName, argTypes, method.getReturnType(), true);
|
||||
generatedOverrides.put(methodKey, 0);
|
||||
|
@ -404,13 +405,13 @@ public final class JavaAdapter implements IdFunctionCall {
|
|||
// has a property of the same name, then an override is intended.
|
||||
boolean isAbstractMethod = Modifier.isAbstract(mods);
|
||||
String methodName = method.getName();
|
||||
if (isAbstractMethod || functionNames.has(methodName)) {
|
||||
if (isAbstractMethod || functionNames.containsKey(methodName)) {
|
||||
// make sure to generate only one instance of a particular
|
||||
// method/signature.
|
||||
Class<?>[] argTypes = method.getParameterTypes();
|
||||
String methodSignature = getMethodSignature(method, argTypes);
|
||||
String methodKey = methodName + methodSignature;
|
||||
if (!generatedOverrides.has(methodKey)) {
|
||||
if (!generatedOverrides.containsKey(methodKey)) {
|
||||
generateMethod(
|
||||
cfw, adapterName, methodName, argTypes, method.getReturnType(), true);
|
||||
generatedOverrides.put(methodKey, 0);
|
||||
|
@ -434,11 +435,10 @@ public final class JavaAdapter implements IdFunctionCall {
|
|||
|
||||
// Generate Java methods for remaining properties that are not
|
||||
// overrides.
|
||||
ObjToIntMap.Iterator iter = new ObjToIntMap.Iterator(functionNames);
|
||||
for (iter.start(); !iter.done(); iter.next()) {
|
||||
String functionName = (String) iter.getKey();
|
||||
if (generatedMethods.has(functionName)) continue;
|
||||
int length = iter.getValue();
|
||||
for (Map.Entry<String, Integer> e : functionNames.entrySet()) {
|
||||
String functionName = e.getKey();
|
||||
if (generatedMethods.containsKey(functionName)) continue;
|
||||
int length = e.getValue();
|
||||
Class<?>[] parms = new Class[length];
|
||||
for (int k = 0; k < length; k++) parms[k] = ScriptRuntime.ObjectClass;
|
||||
generateMethod(cfw, adapterName, functionName, parms, ScriptRuntime.ObjectClass, false);
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Arrays;
|
|||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
@ -1185,10 +1186,10 @@ public class NativeArray extends IdScriptableObject implements List {
|
|||
if (cx.iterating == null) {
|
||||
toplevel = true;
|
||||
iterating = false;
|
||||
cx.iterating = new ObjToIntMap(31);
|
||||
cx.iterating = new HashSet<Scriptable>();
|
||||
} else {
|
||||
toplevel = false;
|
||||
iterating = cx.iterating.has(o);
|
||||
iterating = cx.iterating.contains(o);
|
||||
}
|
||||
|
||||
// Make sure cx.iterating is set to null when done
|
||||
|
@ -1196,7 +1197,7 @@ public class NativeArray extends IdScriptableObject implements List {
|
|||
try {
|
||||
if (!iterating) {
|
||||
// stop recursion
|
||||
cx.iterating.put(o, 0);
|
||||
cx.iterating.add(o);
|
||||
|
||||
// make toSource print null and undefined values in recent versions
|
||||
boolean skipUndefinedAndNull =
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
package org.mozilla.javascript;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import org.mozilla.javascript.ast.Comment;
|
||||
import org.mozilla.javascript.ast.FunctionNode;
|
||||
|
@ -1027,13 +1029,13 @@ public class Node implements Iterable<Node> {
|
|||
public String toString() {
|
||||
if (Token.printTrees) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
toString(new ObjToIntMap(), sb);
|
||||
toString(new HashMap<>(), sb);
|
||||
return sb.toString();
|
||||
}
|
||||
return String.valueOf(type);
|
||||
}
|
||||
|
||||
private void toString(ObjToIntMap printIds, StringBuilder sb) {
|
||||
private void toString(Map<Node, Integer> printIds, StringBuilder sb) {
|
||||
if (Token.printTrees) {
|
||||
sb.append(Token.name(type));
|
||||
if (this instanceof Name) {
|
||||
|
@ -1196,10 +1198,10 @@ public class Node implements Iterable<Node> {
|
|||
}
|
||||
|
||||
private static void toStringTreeHelper(
|
||||
ScriptNode treeTop, Node n, ObjToIntMap printIds, int level, StringBuilder sb) {
|
||||
ScriptNode treeTop, Node n, Map<Node, Integer> printIds, int level, StringBuilder sb) {
|
||||
if (Token.printTrees) {
|
||||
if (printIds == null) {
|
||||
printIds = new ObjToIntMap();
|
||||
printIds = new HashMap<>();
|
||||
generatePrintIds(treeTop, printIds);
|
||||
}
|
||||
for (int i = 0; i != level; ++i) {
|
||||
|
@ -1219,7 +1221,7 @@ public class Node implements Iterable<Node> {
|
|||
}
|
||||
}
|
||||
|
||||
private static void generatePrintIds(Node n, ObjToIntMap map) {
|
||||
private static void generatePrintIds(Node n, Map<Node, Integer> map) {
|
||||
if (Token.printTrees) {
|
||||
map.put(n, map.size());
|
||||
for (Node cursor = n.getFirstChild(); cursor != null; cursor = cursor.getNext()) {
|
||||
|
@ -1228,10 +1230,10 @@ public class Node implements Iterable<Node> {
|
|||
}
|
||||
}
|
||||
|
||||
private static void appendPrintId(Node n, ObjToIntMap printIds, StringBuilder sb) {
|
||||
private static void appendPrintId(Node n, Map<Node, Integer> printIds, StringBuilder sb) {
|
||||
if (Token.printTrees) {
|
||||
if (n != null) {
|
||||
int id = printIds.get(n, -1);
|
||||
int id = printIds.getOrDefault(n, -1);
|
||||
sb.append('#');
|
||||
if (id != -1) {
|
||||
sb.append(id + 1);
|
||||
|
|
|
@ -1,660 +0,0 @@
|
|||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Map to associate objects to integers. The map does not synchronize any of its operation, so
|
||||
* either use it from a single thread or do own synchronization or perform all mutation operations
|
||||
* on one thread before passing the map to others
|
||||
*
|
||||
* @author Igor Bukanov
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ObjToIntMap implements Serializable {
|
||||
private static final long serialVersionUID = -1542220580748809402L;
|
||||
|
||||
// Map implementation via hashtable,
|
||||
// follows "The Art of Computer Programming" by Donald E. Knuth
|
||||
|
||||
// ObjToIntMap is a copy cat of ObjToIntMap with API adjusted to object keys
|
||||
|
||||
public static class Iterator {
|
||||
|
||||
Iterator(ObjToIntMap master) {
|
||||
this.master = master;
|
||||
}
|
||||
|
||||
final void init(Object[] keys, int[] values, int keyCount) {
|
||||
this.keys = keys;
|
||||
this.values = values;
|
||||
this.cursor = -1;
|
||||
this.remaining = keyCount;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
master.initIterator(this);
|
||||
next();
|
||||
}
|
||||
|
||||
public boolean done() {
|
||||
return remaining < 0;
|
||||
}
|
||||
|
||||
public void next() {
|
||||
if (remaining == -1) Kit.codeBug();
|
||||
if (remaining == 0) {
|
||||
remaining = -1;
|
||||
cursor = -1;
|
||||
} else {
|
||||
for (++cursor; ; ++cursor) {
|
||||
Object key = keys[cursor];
|
||||
if (key != null && key != DELETED) {
|
||||
--remaining;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
Object key = keys[cursor];
|
||||
if (key == UniqueTag.NULL_VALUE) {
|
||||
key = null;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return values[cursor];
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
values[cursor] = value;
|
||||
}
|
||||
|
||||
ObjToIntMap master;
|
||||
private int cursor;
|
||||
private int remaining;
|
||||
private Object[] keys;
|
||||
private int[] values;
|
||||
}
|
||||
|
||||
public ObjToIntMap() {
|
||||
this(4);
|
||||
}
|
||||
|
||||
public ObjToIntMap(int keyCountHint) {
|
||||
if (keyCountHint < 0) Kit.codeBug();
|
||||
// Table grow when number of stored keys >= 3/4 of max capacity
|
||||
int minimalCapacity = keyCountHint * 4 / 3;
|
||||
int i;
|
||||
for (i = 2; (1 << i) < minimalCapacity; ++i) {}
|
||||
power = i;
|
||||
if (check && power < 2) Kit.codeBug();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return keyCount == 0;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return keyCount;
|
||||
}
|
||||
|
||||
public boolean has(Object key) {
|
||||
if (key == null) {
|
||||
key = UniqueTag.NULL_VALUE;
|
||||
}
|
||||
return 0 <= findIndex(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get integer value assigned with key.
|
||||
*
|
||||
* @return key integer value or defaultValue if key is absent
|
||||
*/
|
||||
public int get(Object key, int defaultValue) {
|
||||
if (key == null) {
|
||||
key = UniqueTag.NULL_VALUE;
|
||||
}
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
return values[index];
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get integer value assigned with key.
|
||||
*
|
||||
* @return key integer value
|
||||
* @throws RuntimeException if key does not exist
|
||||
*/
|
||||
public int getExisting(Object key) {
|
||||
if (key == null) {
|
||||
key = UniqueTag.NULL_VALUE;
|
||||
}
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
return values[index];
|
||||
}
|
||||
// Key must exist
|
||||
Kit.codeBug();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void put(Object key, int value) {
|
||||
if (key == null) {
|
||||
key = UniqueTag.NULL_VALUE;
|
||||
}
|
||||
int index = ensureIndex(key);
|
||||
values[index] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* If table already contains a key that equals to keyArg, return that key while setting its
|
||||
* value to zero, otherwise add keyArg with 0 value to the table and return it.
|
||||
*/
|
||||
public Object intern(Object keyArg) {
|
||||
boolean nullKey = false;
|
||||
if (keyArg == null) {
|
||||
nullKey = true;
|
||||
keyArg = UniqueTag.NULL_VALUE;
|
||||
}
|
||||
int index = ensureIndex(keyArg);
|
||||
values[index] = 0;
|
||||
return nullKey ? null : keys[index];
|
||||
}
|
||||
|
||||
public void remove(Object key) {
|
||||
if (key == null) {
|
||||
key = UniqueTag.NULL_VALUE;
|
||||
}
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
keys[index] = DELETED;
|
||||
--keyCount;
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
int i = keys.length;
|
||||
while (i != 0) {
|
||||
keys[--i] = null;
|
||||
}
|
||||
keyCount = 0;
|
||||
occupiedCount = 0;
|
||||
}
|
||||
|
||||
public Iterator newIterator() {
|
||||
return new Iterator(this);
|
||||
}
|
||||
|
||||
// The sole purpose of the method is to avoid accessing private fields
|
||||
// from the Iterator inner class to workaround JDK 1.1 compiler bug which
|
||||
// generates code triggering VerifierError on recent JVMs
|
||||
final void initIterator(Iterator i) {
|
||||
i.init(keys, values, keyCount);
|
||||
}
|
||||
|
||||
/** Return array of present keys */
|
||||
public Object[] getKeys() {
|
||||
Object[] array = new Object[keyCount];
|
||||
getKeys(array, 0);
|
||||
return array;
|
||||
}
|
||||
|
||||
public void getKeys(Object[] array, int offset) {
|
||||
int count = keyCount;
|
||||
for (int i = 0; count != 0; ++i) {
|
||||
Object key = keys[i];
|
||||
if (key != null && key != DELETED) {
|
||||
if (key == UniqueTag.NULL_VALUE) {
|
||||
key = null;
|
||||
}
|
||||
array[offset] = key;
|
||||
++offset;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int tableLookupStep(int fraction, int mask, int power) {
|
||||
int shift = 32 - 2 * power;
|
||||
if (shift >= 0) {
|
||||
return ((fraction >>> shift) & mask) | 1;
|
||||
}
|
||||
return (fraction & (mask >>> -shift)) | 1;
|
||||
}
|
||||
|
||||
private int findIndex(Object key) {
|
||||
if (keys != null) {
|
||||
int hash = key.hashCode();
|
||||
int fraction = hash * A;
|
||||
int index = fraction >>> (32 - power);
|
||||
Object test = keys[index];
|
||||
if (test != null) {
|
||||
int N = 1 << power;
|
||||
if (test == key || (values[N + index] == hash && test.equals(key))) {
|
||||
return index;
|
||||
}
|
||||
// Search in table after first failed attempt
|
||||
int mask = N - 1;
|
||||
int step = tableLookupStep(fraction, mask, power);
|
||||
int n = 0;
|
||||
for (; ; ) {
|
||||
if (check) {
|
||||
if (n >= occupiedCount) Kit.codeBug();
|
||||
++n;
|
||||
}
|
||||
index = (index + step) & mask;
|
||||
test = keys[index];
|
||||
if (test == null) {
|
||||
break;
|
||||
}
|
||||
if (test == key || (values[N + index] == hash && test.equals(key))) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Insert key that is not present to table without deleted entries
|
||||
// and enough free space
|
||||
private int insertNewKey(Object key, int hash) {
|
||||
if (check && occupiedCount != keyCount) Kit.codeBug();
|
||||
if (check && keyCount == 1 << power) Kit.codeBug();
|
||||
int fraction = hash * A;
|
||||
int index = fraction >>> (32 - power);
|
||||
int N = 1 << power;
|
||||
if (keys[index] != null) {
|
||||
int mask = N - 1;
|
||||
int step = tableLookupStep(fraction, mask, power);
|
||||
int firstIndex = index;
|
||||
do {
|
||||
if (check && keys[index] == DELETED) Kit.codeBug();
|
||||
index = (index + step) & mask;
|
||||
if (check && firstIndex == index) Kit.codeBug();
|
||||
} while (keys[index] != null);
|
||||
}
|
||||
keys[index] = key;
|
||||
values[N + index] = hash;
|
||||
++occupiedCount;
|
||||
++keyCount;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
private void rehashTable() {
|
||||
if (keys == null) {
|
||||
if (check && keyCount != 0) Kit.codeBug();
|
||||
if (check && occupiedCount != 0) Kit.codeBug();
|
||||
int N = 1 << power;
|
||||
keys = new Object[N];
|
||||
values = new int[2 * N];
|
||||
} else {
|
||||
// Check if removing deleted entries would free enough space
|
||||
if (keyCount * 2 >= occupiedCount) {
|
||||
// Need to grow: less then half of deleted entries
|
||||
++power;
|
||||
}
|
||||
int N = 1 << power;
|
||||
Object[] oldKeys = keys;
|
||||
int[] oldValues = values;
|
||||
int oldN = oldKeys.length;
|
||||
keys = new Object[N];
|
||||
values = new int[2 * N];
|
||||
|
||||
int remaining = keyCount;
|
||||
occupiedCount = keyCount = 0;
|
||||
for (int i = 0; remaining != 0; ++i) {
|
||||
Object key = oldKeys[i];
|
||||
if (key != null && key != DELETED) {
|
||||
int keyHash = oldValues[oldN + i];
|
||||
int index = insertNewKey(key, keyHash);
|
||||
values[index] = oldValues[i];
|
||||
--remaining;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure key index creating one if necessary
|
||||
private int ensureIndex(Object key) {
|
||||
int hash = key.hashCode();
|
||||
int index = -1;
|
||||
int firstDeleted = -1;
|
||||
if (keys != null) {
|
||||
int fraction = hash * A;
|
||||
index = fraction >>> (32 - power);
|
||||
Object test = keys[index];
|
||||
if (test != null) {
|
||||
int N = 1 << power;
|
||||
if (test == key || (values[N + index] == hash && test.equals(key))) {
|
||||
return index;
|
||||
}
|
||||
if (test == DELETED) {
|
||||
firstDeleted = index;
|
||||
}
|
||||
|
||||
// Search in table after first failed attempt
|
||||
int mask = N - 1;
|
||||
int step = tableLookupStep(fraction, mask, power);
|
||||
int n = 0;
|
||||
for (; ; ) {
|
||||
if (check) {
|
||||
if (n >= occupiedCount) Kit.codeBug();
|
||||
++n;
|
||||
}
|
||||
index = (index + step) & mask;
|
||||
test = keys[index];
|
||||
if (test == null) {
|
||||
break;
|
||||
}
|
||||
if (test == key || (values[N + index] == hash && test.equals(key))) {
|
||||
return index;
|
||||
}
|
||||
if (test == DELETED && firstDeleted < 0) {
|
||||
firstDeleted = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Inserting of new key
|
||||
if (check && keys != null && keys[index] != null) Kit.codeBug();
|
||||
if (firstDeleted >= 0) {
|
||||
index = firstDeleted;
|
||||
} else {
|
||||
// Need to consume empty entry: check occupation level
|
||||
if (keys == null || occupiedCount * 4 >= (1 << power) * 3) {
|
||||
// Too litle unused entries: rehash
|
||||
rehashTable();
|
||||
return insertNewKey(key, hash);
|
||||
}
|
||||
++occupiedCount;
|
||||
}
|
||||
keys[index] = key;
|
||||
values[(1 << power) + index] = hash;
|
||||
++keyCount;
|
||||
return index;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
out.defaultWriteObject();
|
||||
|
||||
int count = keyCount;
|
||||
for (int i = 0; count != 0; ++i) {
|
||||
Object key = keys[i];
|
||||
if (key != null && key != DELETED) {
|
||||
--count;
|
||||
out.writeObject(key);
|
||||
out.writeInt(values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
|
||||
int writtenKeyCount = keyCount;
|
||||
if (writtenKeyCount != 0) {
|
||||
keyCount = 0;
|
||||
int N = 1 << power;
|
||||
keys = new Object[N];
|
||||
values = new int[2 * N];
|
||||
for (int i = 0; i != writtenKeyCount; ++i) {
|
||||
Object key = in.readObject();
|
||||
int hash = key.hashCode();
|
||||
int index = insertNewKey(key, hash);
|
||||
values[index] = in.readInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32)
|
||||
// See Knuth etc.
|
||||
private static final int A = 0x9e3779b9;
|
||||
|
||||
private static final Object DELETED = new Object();
|
||||
|
||||
// Structure of kyes and values arrays (N == 1 << power):
|
||||
// keys[0 <= i < N]: key value or null or DELETED mark
|
||||
// values[0 <= i < N]: value of key at keys[i]
|
||||
// values[N <= i < 2*N]: hash code of key at keys[i-N]
|
||||
|
||||
private transient Object[] keys;
|
||||
private transient int[] values;
|
||||
|
||||
private int power;
|
||||
private int keyCount;
|
||||
private transient int occupiedCount; // == keyCount + deleted_count
|
||||
|
||||
// If true, enables consitency checks
|
||||
private static final boolean check = false;
|
||||
|
||||
/* TEST START
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (!check) {
|
||||
System.err.println("Set check to true and re-run");
|
||||
throw new RuntimeException("Set check to true and re-run");
|
||||
}
|
||||
|
||||
ObjToIntMap map;
|
||||
map = new ObjToIntMap(0);
|
||||
testHash(map, 3);
|
||||
map = new ObjToIntMap(0);
|
||||
testHash(map, 10 * 1000);
|
||||
map = new ObjToIntMap();
|
||||
testHash(map, 10 * 1000);
|
||||
map = new ObjToIntMap(30 * 1000);
|
||||
testHash(map, 10 * 100);
|
||||
map.clear();
|
||||
testHash(map, 4);
|
||||
map = new ObjToIntMap(0);
|
||||
testHash(map, 10 * 100);
|
||||
}
|
||||
|
||||
private static void testHash(ObjToIntMap map, int N) {
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i);
|
||||
check(-1 == map.get(key, -1));
|
||||
map.put(key, i);
|
||||
check(i == map.get(key, -1));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i);
|
||||
map.put(key, i);
|
||||
check(i == map.get(key, -1));
|
||||
}
|
||||
|
||||
check(map.size() == N);
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
Object[] keys = map.getKeys();
|
||||
check(keys.length == N);
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = keys[i];
|
||||
check(map.has(key));
|
||||
}
|
||||
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i);
|
||||
check(i == map.get(key, -1));
|
||||
}
|
||||
|
||||
int Nsqrt = -1;
|
||||
for (int i = 0; ; ++i) {
|
||||
if (i * i >= N) {
|
||||
Nsqrt = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i * i);
|
||||
map.put(key, i);
|
||||
check(i == map.get(key, -1));
|
||||
}
|
||||
|
||||
check(map.size() == 2 * N - Nsqrt);
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i * i);
|
||||
check(i == map.get(key, -1));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(-1 - i * i);
|
||||
map.put(key, i);
|
||||
check(i == map.get(key, -1));
|
||||
}
|
||||
|
||||
check(map.size() == 3 * N - Nsqrt);
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(-1 - i * i);
|
||||
map.remove(key);
|
||||
check(!map.has(key));
|
||||
}
|
||||
|
||||
check(map.size() == 2 * N - Nsqrt);
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i * i);
|
||||
check(i == map.get(key, -1));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i);
|
||||
int j = intSqrt(i);
|
||||
if (j * j == i) {
|
||||
check(j == map.get(key, -1));
|
||||
}else {
|
||||
check(i == map.get(key, -1));
|
||||
}
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i * i);
|
||||
map.remove(key);
|
||||
check(-2 == map.get(key, -2));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i);
|
||||
map.put(key, i);
|
||||
check(i == map.get(key, -2));
|
||||
}
|
||||
|
||||
check(map.size() == N);
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i);
|
||||
check(i == map.get(key, -1));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
ObjToIntMap copy = (ObjToIntMap)writeAndRead(map);
|
||||
check(copy.size() == N);
|
||||
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Object key = testKey(i);
|
||||
check(i == copy.get(key, -1));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
checkSameMaps(copy, map);
|
||||
|
||||
System.out.println(); System.out.flush();
|
||||
}
|
||||
|
||||
private static void checkSameMaps(ObjToIntMap map1, ObjToIntMap map2) {
|
||||
check(map1.size() == map2.size());
|
||||
Object[] keys = map1.getKeys();
|
||||
check(keys.length == map1.size());
|
||||
for (int i = 0; i != keys.length; ++i) {
|
||||
check(map1.get(keys[i], -1) == map2.get(keys[i], -1));
|
||||
}
|
||||
}
|
||||
|
||||
private static void check(boolean condition) {
|
||||
if (!condition) Kit.codeBug();
|
||||
}
|
||||
|
||||
private static Object[] testPool;
|
||||
|
||||
private static Object testKey(int i) {
|
||||
int MAX_POOL = 100;
|
||||
if (0 <= i && i < MAX_POOL) {
|
||||
if (testPool != null && testPool[i] != null) {
|
||||
return testPool[i];
|
||||
}
|
||||
}
|
||||
Object x = Double.valueOf(i + 0.5);
|
||||
if (0 <= i && i < MAX_POOL) {
|
||||
if (testPool == null) {
|
||||
testPool = new Object[MAX_POOL];
|
||||
}
|
||||
testPool[i] = x;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
private static int intSqrt(int i) {
|
||||
int approx = (int)Math.sqrt(i) + 1;
|
||||
while (approx * approx > i) {
|
||||
--approx;
|
||||
}
|
||||
return approx;
|
||||
}
|
||||
|
||||
private static Object writeAndRead(Object obj) {
|
||||
try {
|
||||
java.io.ByteArrayOutputStream
|
||||
bos = new java.io.ByteArrayOutputStream();
|
||||
java.io.ObjectOutputStream
|
||||
out = new java.io.ObjectOutputStream(bos);
|
||||
out.writeObject(obj);
|
||||
out.close();
|
||||
byte[] data = bos.toByteArray();
|
||||
java.io.ByteArrayInputStream
|
||||
bis = new java.io.ByteArrayInputStream(data);
|
||||
java.io.ObjectInputStream
|
||||
in = new java.io.ObjectInputStream(bis);
|
||||
Object result = in.readObject();
|
||||
in.close();
|
||||
return result;
|
||||
}catch (Exception ex) {
|
||||
throw new RuntimeException("Unexpected");
|
||||
}
|
||||
}
|
||||
|
||||
// TEST END */
|
||||
|
||||
}
|
|
@ -13,6 +13,7 @@ import java.math.BigInteger;
|
|||
import java.math.MathContext;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
|
@ -1142,10 +1143,10 @@ public class ScriptRuntime {
|
|||
if (cx.iterating == null) {
|
||||
toplevel = true;
|
||||
iterating = false;
|
||||
cx.iterating = new ObjToIntMap(31);
|
||||
cx.iterating = new HashSet<>();
|
||||
} else {
|
||||
toplevel = false;
|
||||
iterating = cx.iterating.has(thisObj);
|
||||
iterating = cx.iterating.contains(thisObj);
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder(128);
|
||||
|
@ -1158,7 +1159,7 @@ public class ScriptRuntime {
|
|||
// so we don't leak memory
|
||||
try {
|
||||
if (!iterating) {
|
||||
cx.iterating.intern(thisObj); // stop recursion.
|
||||
cx.iterating.add(thisObj); // stop recursion.
|
||||
Object[] ids = thisObj.getIds();
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
Object id = ids[i];
|
||||
|
@ -2247,7 +2248,7 @@ public class ScriptRuntime {
|
|||
private static final long serialVersionUID = 1L;
|
||||
Scriptable obj;
|
||||
Object[] ids;
|
||||
ObjToIntMap used;
|
||||
HashSet<Object> used;
|
||||
Object currentId;
|
||||
int index;
|
||||
int enumType; /* one of ENUM_INIT_KEYS, ENUM_INIT_VALUES,
|
||||
|
@ -2396,7 +2397,7 @@ public class ScriptRuntime {
|
|||
continue;
|
||||
}
|
||||
Object id = x.ids[x.index++];
|
||||
if (x.used != null && x.used.has(id)) {
|
||||
if (x.used != null && x.used.contains(id)) {
|
||||
continue;
|
||||
}
|
||||
if (id instanceof Symbol) {
|
||||
|
@ -2486,10 +2487,10 @@ public class ScriptRuntime {
|
|||
Object[] previous = x.ids;
|
||||
int L = previous.length;
|
||||
if (x.used == null) {
|
||||
x.used = new ObjToIntMap(L);
|
||||
x.used = new HashSet<>();
|
||||
}
|
||||
for (int i = 0; i != L; ++i) {
|
||||
x.used.intern(previous[i]);
|
||||
x.used.add(previous[i]);
|
||||
}
|
||||
}
|
||||
x.ids = ids;
|
||||
|
|
|
@ -2334,7 +2334,7 @@ public abstract class ScriptableObject
|
|||
return ScriptRuntime.emptyArgs;
|
||||
}
|
||||
Object[] result = obj.getIds();
|
||||
ObjToIntMap map = null;
|
||||
HashSet<Object> map = null;
|
||||
for (; ; ) {
|
||||
obj = obj.getPrototype();
|
||||
if (obj == null) {
|
||||
|
@ -2349,18 +2349,18 @@ public abstract class ScriptableObject
|
|||
result = ids;
|
||||
continue;
|
||||
}
|
||||
map = new ObjToIntMap(result.length + ids.length);
|
||||
map = new HashSet<>();
|
||||
for (int i = 0; i != result.length; ++i) {
|
||||
map.intern(result[i]);
|
||||
map.add(result[i]);
|
||||
}
|
||||
result = null; // Allow to GC the result
|
||||
}
|
||||
for (int i = 0; i != ids.length; ++i) {
|
||||
map.intern(ids[i]);
|
||||
map.add(ids[i]);
|
||||
}
|
||||
}
|
||||
if (map != null) {
|
||||
result = map.getKeys();
|
||||
result = map.toArray();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.mozilla.javascript;
|
|||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This class implements the JavaScript scanner.
|
||||
|
@ -782,7 +783,7 @@ class TokenStream implements Parser.CurrentPositionReporter {
|
|||
}
|
||||
// Save the string in case we need to use in
|
||||
// object literal definitions.
|
||||
this.string = (String) allStrings.intern(str);
|
||||
this.string = internString(str);
|
||||
if (result != Token.RESERVED) {
|
||||
return result;
|
||||
} else if (parser.compilerEnv.getLanguageVersion() >= Context.VERSION_ES6) {
|
||||
|
@ -807,7 +808,7 @@ class TokenStream implements Parser.CurrentPositionReporter {
|
|||
return Token.ERROR;
|
||||
}
|
||||
|
||||
this.string = (String) allStrings.intern(str);
|
||||
this.string = internString(str);
|
||||
return Token.NAME;
|
||||
}
|
||||
|
||||
|
@ -1114,7 +1115,7 @@ class TokenStream implements Parser.CurrentPositionReporter {
|
|||
}
|
||||
|
||||
String str = getStringFromBuffer();
|
||||
this.string = (String) allStrings.intern(str);
|
||||
this.string = internString(str);
|
||||
return Token.STRING;
|
||||
}
|
||||
|
||||
|
@ -1403,6 +1404,20 @@ class TokenStream implements Parser.CurrentPositionReporter {
|
|||
return c;
|
||||
}
|
||||
|
||||
// Use a HashMap to ensure that we only have one copy -- the original one
|
||||
// of any particular string. Yes, the "String.intern" function also does this,
|
||||
// but this is how Rhino has worked for years and it's not clear that we
|
||||
// want to make the JVM-wide intern pool as big as it might happen if we
|
||||
// used that.
|
||||
private String internString(String s) {
|
||||
String existing = allStrings.putIfAbsent(s, s);
|
||||
if (existing == null) {
|
||||
// First time we saw it
|
||||
return s;
|
||||
}
|
||||
return existing;
|
||||
}
|
||||
|
||||
private static boolean isAlpha(int c) {
|
||||
// Use 'Z' < 'a'
|
||||
if (c <= 'Z') {
|
||||
|
@ -2421,7 +2436,7 @@ class TokenStream implements Parser.CurrentPositionReporter {
|
|||
|
||||
private char[] stringBuffer = new char[128];
|
||||
private int stringBufferTop;
|
||||
private ObjToIntMap allStrings = new ObjToIntMap(50);
|
||||
private final HashMap<String, String> allStrings = new HashMap<>();
|
||||
|
||||
// Room to backtrace from to < on failed match of the last - in <!--
|
||||
private final int[] ungetBuffer = new int[3];
|
||||
|
|
|
@ -1,629 +0,0 @@
|
|||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Map to associate non-negative integers to objects or integers. The map does not synchronize any
|
||||
* of its operation, so either use it from a single thread or do own synchronization or perform all
|
||||
* mutation operations on one thread before passing the map to others.
|
||||
*
|
||||
* @author Igor Bukanov
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class UintMap implements Serializable {
|
||||
private static final long serialVersionUID = 4242698212885848444L;
|
||||
|
||||
// Map implementation via hashtable,
|
||||
// follows "The Art of Computer Programming" by Donald E. Knuth
|
||||
|
||||
public UintMap() {
|
||||
this(4);
|
||||
}
|
||||
|
||||
public UintMap(int initialCapacity) {
|
||||
if (initialCapacity < 0) Kit.codeBug();
|
||||
// Table grow when number of stored keys >= 3/4 of max capacity
|
||||
int minimalCapacity = initialCapacity * 4 / 3;
|
||||
int i;
|
||||
for (i = 2; (1 << i) < minimalCapacity; ++i) {}
|
||||
power = i;
|
||||
if (check && power < 2) Kit.codeBug();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return keyCount == 0;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return keyCount;
|
||||
}
|
||||
|
||||
public boolean has(int key) {
|
||||
if (key < 0) Kit.codeBug();
|
||||
return 0 <= findIndex(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object value assigned with key.
|
||||
*
|
||||
* @return key object value or null if key is absent
|
||||
*/
|
||||
public Object getObject(int key) {
|
||||
if (key < 0) Kit.codeBug();
|
||||
if (values != null) {
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
return values[index];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get integer value assigned with key.
|
||||
*
|
||||
* @return key integer value or defaultValue if key is absent
|
||||
*/
|
||||
public int getInt(int key, int defaultValue) {
|
||||
if (key < 0) Kit.codeBug();
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
if (ivaluesShift != 0) {
|
||||
return keys[ivaluesShift + index];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get integer value assigned with key.
|
||||
*
|
||||
* @return key integer value or defaultValue if key does not exist or does not have int value
|
||||
* @throws RuntimeException if key does not exist
|
||||
*/
|
||||
public int getExistingInt(int key) {
|
||||
if (key < 0) Kit.codeBug();
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
if (ivaluesShift != 0) {
|
||||
return keys[ivaluesShift + index];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// Key must exist
|
||||
Kit.codeBug();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Set object value of the key. If key does not exist, also set its int value to 0. */
|
||||
public void put(int key, Object value) {
|
||||
if (key < 0) Kit.codeBug();
|
||||
int index = ensureIndex(key, false);
|
||||
if (values == null) {
|
||||
values = new Object[1 << power];
|
||||
}
|
||||
values[index] = value;
|
||||
}
|
||||
|
||||
/** Set int value of the key. If key does not exist, also set its object value to null. */
|
||||
public void put(int key, int value) {
|
||||
if (key < 0) Kit.codeBug();
|
||||
int index = ensureIndex(key, true);
|
||||
if (ivaluesShift == 0) {
|
||||
int N = 1 << power;
|
||||
// keys.length can be N * 2 after clear which set ivaluesShift to 0
|
||||
if (keys.length != N * 2) {
|
||||
int[] tmp = new int[N * 2];
|
||||
System.arraycopy(keys, 0, tmp, 0, N);
|
||||
keys = tmp;
|
||||
}
|
||||
ivaluesShift = N;
|
||||
}
|
||||
keys[ivaluesShift + index] = value;
|
||||
}
|
||||
|
||||
public void remove(int key) {
|
||||
if (key < 0) Kit.codeBug();
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
keys[index] = DELETED;
|
||||
--keyCount;
|
||||
// Allow to GC value and make sure that new key with the deleted
|
||||
// slot shall get proper default values
|
||||
if (values != null) {
|
||||
values[index] = null;
|
||||
}
|
||||
if (ivaluesShift != 0) {
|
||||
keys[ivaluesShift + index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
int N = 1 << power;
|
||||
if (keys != null) {
|
||||
for (int i = 0; i != N; ++i) {
|
||||
keys[i] = EMPTY;
|
||||
}
|
||||
if (values != null) {
|
||||
for (int i = 0; i != N; ++i) {
|
||||
values[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
ivaluesShift = 0;
|
||||
keyCount = 0;
|
||||
occupiedCount = 0;
|
||||
}
|
||||
|
||||
/** Return array of present keys */
|
||||
public int[] getKeys() {
|
||||
int[] keys = this.keys;
|
||||
int n = keyCount;
|
||||
int[] result = new int[n];
|
||||
for (int i = 0; n != 0; ++i) {
|
||||
int entry = keys[i];
|
||||
if (entry != EMPTY && entry != DELETED) {
|
||||
result[--n] = entry;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int tableLookupStep(int fraction, int mask, int power) {
|
||||
int shift = 32 - 2 * power;
|
||||
if (shift >= 0) {
|
||||
return ((fraction >>> shift) & mask) | 1;
|
||||
}
|
||||
return (fraction & (mask >>> -shift)) | 1;
|
||||
}
|
||||
|
||||
private int findIndex(int key) {
|
||||
int[] keys = this.keys;
|
||||
if (keys != null) {
|
||||
int fraction = key * A;
|
||||
int index = fraction >>> (32 - power);
|
||||
int entry = keys[index];
|
||||
if (entry == key) {
|
||||
return index;
|
||||
}
|
||||
if (entry != EMPTY) {
|
||||
// Search in table after first failed attempt
|
||||
int mask = (1 << power) - 1;
|
||||
int step = tableLookupStep(fraction, mask, power);
|
||||
int n = 0;
|
||||
do {
|
||||
if (check) {
|
||||
if (n >= occupiedCount) Kit.codeBug();
|
||||
++n;
|
||||
}
|
||||
index = (index + step) & mask;
|
||||
entry = keys[index];
|
||||
if (entry == key) {
|
||||
return index;
|
||||
}
|
||||
} while (entry != EMPTY);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Insert key that is not present to table without deleted entries
|
||||
// and enough free space
|
||||
private int insertNewKey(int key) {
|
||||
if (check && occupiedCount != keyCount) Kit.codeBug();
|
||||
if (check && keyCount == 1 << power) Kit.codeBug();
|
||||
int[] keys = this.keys;
|
||||
int fraction = key * A;
|
||||
int index = fraction >>> (32 - power);
|
||||
if (keys[index] != EMPTY) {
|
||||
int mask = (1 << power) - 1;
|
||||
int step = tableLookupStep(fraction, mask, power);
|
||||
int firstIndex = index;
|
||||
do {
|
||||
if (check && keys[index] == DELETED) Kit.codeBug();
|
||||
index = (index + step) & mask;
|
||||
if (check && firstIndex == index) Kit.codeBug();
|
||||
} while (keys[index] != EMPTY);
|
||||
}
|
||||
keys[index] = key;
|
||||
++occupiedCount;
|
||||
++keyCount;
|
||||
return index;
|
||||
}
|
||||
|
||||
private void rehashTable(boolean ensureIntSpace) {
|
||||
if (keys != null) {
|
||||
// Check if removing deleted entries would free enough space
|
||||
if (keyCount * 2 >= occupiedCount) {
|
||||
// Need to grow: less then half of deleted entries
|
||||
++power;
|
||||
}
|
||||
}
|
||||
int N = 1 << power;
|
||||
int[] old = keys;
|
||||
int oldShift = ivaluesShift;
|
||||
if (oldShift == 0 && !ensureIntSpace) {
|
||||
keys = new int[N];
|
||||
} else {
|
||||
ivaluesShift = N;
|
||||
keys = new int[N * 2];
|
||||
}
|
||||
for (int i = 0; i != N; ++i) {
|
||||
keys[i] = EMPTY;
|
||||
}
|
||||
|
||||
Object[] oldValues = values;
|
||||
if (oldValues != null) {
|
||||
values = new Object[N];
|
||||
}
|
||||
|
||||
int oldCount = keyCount;
|
||||
occupiedCount = 0;
|
||||
if (oldCount != 0) {
|
||||
keyCount = 0;
|
||||
for (int i = 0, remaining = oldCount; remaining != 0; ++i) {
|
||||
int key = old[i];
|
||||
if (key != EMPTY && key != DELETED) {
|
||||
int index = insertNewKey(key);
|
||||
if (oldValues != null) {
|
||||
values[index] = oldValues[i];
|
||||
}
|
||||
if (oldShift != 0) {
|
||||
keys[ivaluesShift + index] = old[oldShift + i];
|
||||
}
|
||||
--remaining;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure key index creating one if necessary
|
||||
private int ensureIndex(int key, boolean intType) {
|
||||
int index = -1;
|
||||
int firstDeleted = -1;
|
||||
int[] keys = this.keys;
|
||||
if (keys != null) {
|
||||
int fraction = key * A;
|
||||
index = fraction >>> (32 - power);
|
||||
int entry = keys[index];
|
||||
if (entry == key) {
|
||||
return index;
|
||||
}
|
||||
if (entry != EMPTY) {
|
||||
if (entry == DELETED) {
|
||||
firstDeleted = index;
|
||||
}
|
||||
// Search in table after first failed attempt
|
||||
int mask = (1 << power) - 1;
|
||||
int step = tableLookupStep(fraction, mask, power);
|
||||
int n = 0;
|
||||
do {
|
||||
if (check) {
|
||||
if (n >= occupiedCount) Kit.codeBug();
|
||||
++n;
|
||||
}
|
||||
index = (index + step) & mask;
|
||||
entry = keys[index];
|
||||
if (entry == key) {
|
||||
return index;
|
||||
}
|
||||
if (entry == DELETED && firstDeleted < 0) {
|
||||
firstDeleted = index;
|
||||
}
|
||||
} while (entry != EMPTY);
|
||||
}
|
||||
}
|
||||
// Inserting of new key
|
||||
if (check && keys != null && keys[index] != EMPTY) Kit.codeBug();
|
||||
if (firstDeleted >= 0) {
|
||||
index = firstDeleted;
|
||||
} else {
|
||||
// Need to consume empty entry: check occupation level
|
||||
if (keys == null || occupiedCount * 4 >= (1 << power) * 3) {
|
||||
// Too litle unused entries: rehash
|
||||
rehashTable(intType);
|
||||
return insertNewKey(key);
|
||||
}
|
||||
++occupiedCount;
|
||||
}
|
||||
keys[index] = key;
|
||||
++keyCount;
|
||||
return index;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
out.defaultWriteObject();
|
||||
|
||||
int count = keyCount;
|
||||
if (count != 0) {
|
||||
boolean hasIntValues = (ivaluesShift != 0);
|
||||
boolean hasObjectValues = (values != null);
|
||||
out.writeBoolean(hasIntValues);
|
||||
out.writeBoolean(hasObjectValues);
|
||||
|
||||
for (int i = 0; count != 0; ++i) {
|
||||
int key = keys[i];
|
||||
if (key != EMPTY && key != DELETED) {
|
||||
--count;
|
||||
out.writeInt(key);
|
||||
if (hasIntValues) {
|
||||
out.writeInt(keys[ivaluesShift + i]);
|
||||
}
|
||||
if (hasObjectValues) {
|
||||
out.writeObject(values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
|
||||
int writtenKeyCount = keyCount;
|
||||
if (writtenKeyCount != 0) {
|
||||
keyCount = 0;
|
||||
boolean hasIntValues = in.readBoolean();
|
||||
boolean hasObjectValues = in.readBoolean();
|
||||
|
||||
int N = 1 << power;
|
||||
if (hasIntValues) {
|
||||
keys = new int[2 * N];
|
||||
ivaluesShift = N;
|
||||
} else {
|
||||
keys = new int[N];
|
||||
}
|
||||
for (int i = 0; i != N; ++i) {
|
||||
keys[i] = EMPTY;
|
||||
}
|
||||
if (hasObjectValues) {
|
||||
values = new Object[N];
|
||||
}
|
||||
for (int i = 0; i != writtenKeyCount; ++i) {
|
||||
int key = in.readInt();
|
||||
int index = insertNewKey(key);
|
||||
if (hasIntValues) {
|
||||
int ivalue = in.readInt();
|
||||
keys[ivaluesShift + index] = ivalue;
|
||||
}
|
||||
if (hasObjectValues) {
|
||||
values[index] = in.readObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32)
|
||||
// See Knuth etc.
|
||||
private static final int A = 0x9e3779b9;
|
||||
|
||||
private static final int EMPTY = -1;
|
||||
private static final int DELETED = -2;
|
||||
|
||||
// Structure of kyes and values arrays (N == 1 << power):
|
||||
// keys[0 <= i < N]: key value or EMPTY or DELETED mark
|
||||
// values[0 <= i < N]: value of key at keys[i]
|
||||
// keys[N <= i < 2N]: int values of keys at keys[i - N]
|
||||
|
||||
private transient int[] keys;
|
||||
private transient Object[] values;
|
||||
|
||||
private int power;
|
||||
private int keyCount;
|
||||
private transient int occupiedCount; // == keyCount + deleted_count
|
||||
|
||||
// If ivaluesShift != 0, keys[ivaluesShift + index] contains integer
|
||||
// values associated with keys
|
||||
private transient int ivaluesShift;
|
||||
|
||||
// If true, enables consitency checks
|
||||
private static final boolean check = false;
|
||||
|
||||
/* TEST START
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (!check) {
|
||||
System.err.println("Set check to true and re-run");
|
||||
throw new RuntimeException("Set check to true and re-run");
|
||||
}
|
||||
|
||||
UintMap map;
|
||||
map = new UintMap();
|
||||
testHash(map, 2);
|
||||
map = new UintMap();
|
||||
testHash(map, 10 * 1000);
|
||||
map = new UintMap(30 * 1000);
|
||||
testHash(map, 10 * 100);
|
||||
map.clear();
|
||||
testHash(map, 4);
|
||||
map = new UintMap(0);
|
||||
testHash(map, 10 * 100);
|
||||
}
|
||||
|
||||
private static void testHash(UintMap map, int N) {
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
map.put(i, i);
|
||||
check(i == map.getInt(i, -1));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
map.put(i, i);
|
||||
check(i == map.getInt(i, -1));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
map.put(i, Integer.valueOf(i));
|
||||
check(-1 == map.getInt(i, -1));
|
||||
Integer obj = (Integer)map.getObject(i);
|
||||
check(obj != null && i == obj.intValue());
|
||||
}
|
||||
|
||||
check(map.size() == N);
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
int[] keys = map.getKeys();
|
||||
check(keys.length == N);
|
||||
for (int i = 0; i != N; ++i) {
|
||||
int key = keys[i];
|
||||
check(map.has(key));
|
||||
check(!map.isIntType(key));
|
||||
check(map.isObjectType(key));
|
||||
Integer obj = (Integer) map.getObject(key);
|
||||
check(obj != null && key == obj.intValue());
|
||||
}
|
||||
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
check(-1 == map.getInt(i, -1));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
map.put(i * i, i);
|
||||
check(i == map.getInt(i * i, -1));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
check(i == map.getInt(i * i, -1));
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
map.put(i * i, Integer.valueOf(i));
|
||||
check(-1 == map.getInt(i * i, -1));
|
||||
map.remove(i * i);
|
||||
check(!map.has(i * i));
|
||||
map.put(i * i, i);
|
||||
check(map.isIntType(i * i));
|
||||
check(null == map.getObject(i * i));
|
||||
map.remove(i * i);
|
||||
check(!map.isObjectType(i * i));
|
||||
check(!map.isIntType(i * i));
|
||||
}
|
||||
|
||||
int old_size = map.size();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
map.remove(i * i);
|
||||
check(map.size() == old_size);
|
||||
}
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
map.clear();
|
||||
check(map.size() == 0);
|
||||
for (int i = 0; i != N; ++i) {
|
||||
map.put(i * i, i);
|
||||
map.put(i * i + 1, Double.valueOf(i+0.5));
|
||||
}
|
||||
checkSameMaps(map, (UintMap)writeAndRead(map));
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
map = new UintMap(0);
|
||||
checkSameMaps(map, (UintMap)writeAndRead(map));
|
||||
map = new UintMap(1);
|
||||
checkSameMaps(map, (UintMap)writeAndRead(map));
|
||||
map = new UintMap(1000);
|
||||
checkSameMaps(map, (UintMap)writeAndRead(map));
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
map = new UintMap(N / 10);
|
||||
for (int i = 0; i != N; ++i) {
|
||||
map.put(2*i+1, i);
|
||||
}
|
||||
checkSameMaps(map, (UintMap)writeAndRead(map));
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
map = new UintMap(N / 10);
|
||||
for (int i = 0; i != N; ++i) {
|
||||
map.put(2*i+1, i);
|
||||
}
|
||||
for (int i = 0; i != N / 2; ++i) {
|
||||
map.remove(2*i+1);
|
||||
}
|
||||
checkSameMaps(map, (UintMap)writeAndRead(map));
|
||||
|
||||
System.out.print("."); System.out.flush();
|
||||
map = new UintMap();
|
||||
for (int i = 0; i != N; ++i) {
|
||||
map.put(2*i+1, Double.valueOf(i + 10));
|
||||
}
|
||||
for (int i = 0; i != N / 2; ++i) {
|
||||
map.remove(2*i+1);
|
||||
}
|
||||
checkSameMaps(map, (UintMap)writeAndRead(map));
|
||||
|
||||
System.out.println(); System.out.flush();
|
||||
|
||||
}
|
||||
|
||||
private static void checkSameMaps(UintMap map1, UintMap map2) {
|
||||
check(map1.size() == map2.size());
|
||||
int[] keys = map1.getKeys();
|
||||
check(keys.length == map1.size());
|
||||
for (int i = 0; i != keys.length; ++i) {
|
||||
int key = keys[i];
|
||||
check(map2.has(key));
|
||||
check(map1.isObjectType(key) == map2.isObjectType(key));
|
||||
check(map1.isIntType(key) == map2.isIntType(key));
|
||||
Object o1 = map1.getObject(key);
|
||||
Object o2 = map2.getObject(key);
|
||||
if (map1.isObjectType(key)) {
|
||||
check(o1.equals(o2));
|
||||
}else {
|
||||
check(map1.getObject(key) == null);
|
||||
check(map2.getObject(key) == null);
|
||||
}
|
||||
if (map1.isIntType(key)) {
|
||||
check(map1.getExistingInt(key) == map2.getExistingInt(key));
|
||||
}else {
|
||||
check(map1.getInt(key, -10) == -10);
|
||||
check(map1.getInt(key, -11) == -11);
|
||||
check(map2.getInt(key, -10) == -10);
|
||||
check(map2.getInt(key, -11) == -11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void check(boolean condition) {
|
||||
if (!condition) Kit.codeBug();
|
||||
}
|
||||
|
||||
private static Object writeAndRead(Object obj) {
|
||||
try {
|
||||
java.io.ByteArrayOutputStream
|
||||
bos = new java.io.ByteArrayOutputStream();
|
||||
java.io.ObjectOutputStream
|
||||
out = new java.io.ObjectOutputStream(bos);
|
||||
out.writeObject(obj);
|
||||
out.close();
|
||||
byte[] data = bos.toByteArray();
|
||||
java.io.ByteArrayInputStream
|
||||
bis = new java.io.ByteArrayInputStream(data);
|
||||
java.io.ObjectInputStream
|
||||
in = new java.io.ObjectInputStream(bis);
|
||||
Object result = in.readObject();
|
||||
in.close();
|
||||
return result;
|
||||
}catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
throw new RuntimeException("Unexpected");
|
||||
}
|
||||
}
|
||||
|
||||
// TEST END */
|
||||
}
|
|
@ -9,9 +9,10 @@ import java.io.StringWriter;
|
|||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.mozilla.javascript.Node;
|
||||
import org.mozilla.javascript.ObjToIntMap;
|
||||
import org.mozilla.javascript.Token;
|
||||
import org.mozilla.javascript.ast.Jump;
|
||||
|
||||
|
@ -19,14 +20,12 @@ class Block {
|
|||
|
||||
private static class FatBlock {
|
||||
|
||||
private static Block[] reduceToArray(ObjToIntMap map) {
|
||||
private static Block[] reduceToArray(Set<FatBlock> map) {
|
||||
Block[] result = null;
|
||||
if (!map.isEmpty()) {
|
||||
result = new Block[map.size()];
|
||||
int i = 0;
|
||||
ObjToIntMap.Iterator iter = map.newIterator();
|
||||
for (iter.start(); !iter.done(); iter.next()) {
|
||||
FatBlock fb = (FatBlock) iter.getKey();
|
||||
for (FatBlock fb : map) {
|
||||
result[i++] = fb.realBlock;
|
||||
}
|
||||
}
|
||||
|
@ -34,11 +33,11 @@ class Block {
|
|||
}
|
||||
|
||||
void addSuccessor(FatBlock b) {
|
||||
successors.put(b, 0);
|
||||
successors.add(b);
|
||||
}
|
||||
|
||||
void addPredecessor(FatBlock b) {
|
||||
predecessors.put(b, 0);
|
||||
predecessors.add(b);
|
||||
}
|
||||
|
||||
Block[] getSuccessors() {
|
||||
|
@ -50,9 +49,9 @@ class Block {
|
|||
}
|
||||
|
||||
// all the Blocks that come immediately after this
|
||||
private ObjToIntMap successors = new ObjToIntMap();
|
||||
private final HashSet<FatBlock> successors = new HashSet<>();
|
||||
// all the Blocks that come immediately before this
|
||||
private ObjToIntMap predecessors = new ObjToIntMap();
|
||||
private final HashSet<FatBlock> predecessors = new HashSet<>();
|
||||
|
||||
Block realBlock;
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
package org.mozilla.javascript.optimizer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import org.mozilla.javascript.CompilerEnvirons;
|
||||
import org.mozilla.javascript.IRFactory;
|
||||
import org.mozilla.javascript.JavaAdapter;
|
||||
import org.mozilla.javascript.ObjToIntMap;
|
||||
import org.mozilla.javascript.Parser;
|
||||
import org.mozilla.javascript.ScriptRuntime;
|
||||
import org.mozilla.javascript.ast.AstRoot;
|
||||
|
@ -143,7 +143,7 @@ public class ClassCompiler {
|
|||
return new Object[] {scriptClassName, scriptClassBytes};
|
||||
}
|
||||
int functionCount = tree.getFunctionCount();
|
||||
ObjToIntMap functionNames = new ObjToIntMap(functionCount);
|
||||
HashMap<String, Integer> functionNames = new HashMap<>();
|
||||
for (int i = 0; i != functionCount; ++i) {
|
||||
FunctionNode ofn = tree.getFunctionNode(i);
|
||||
String name = ofn.getName();
|
||||
|
|
|
@ -27,7 +27,6 @@ import org.mozilla.javascript.Function;
|
|||
import org.mozilla.javascript.GeneratedClassLoader;
|
||||
import org.mozilla.javascript.Kit;
|
||||
import org.mozilla.javascript.NativeFunction;
|
||||
import org.mozilla.javascript.ObjToIntMap;
|
||||
import org.mozilla.javascript.RhinoException;
|
||||
import org.mozilla.javascript.Script;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
@ -232,7 +231,7 @@ public class Codegen implements Evaluator {
|
|||
scriptOrFnNodes = new ScriptNode[count];
|
||||
x.toArray(scriptOrFnNodes);
|
||||
|
||||
scriptOrFnIndexes = new ObjToIntMap(count);
|
||||
scriptOrFnIndexes = new HashMap<>();
|
||||
for (int i = 0; i != count; ++i) {
|
||||
scriptOrFnIndexes.put(scriptOrFnNodes[i], i);
|
||||
}
|
||||
|
@ -1231,7 +1230,7 @@ public class Codegen implements Evaluator {
|
|||
}
|
||||
|
||||
int getIndex(ScriptNode n) {
|
||||
return scriptOrFnIndexes.getExisting(n);
|
||||
return scriptOrFnIndexes.get(n);
|
||||
}
|
||||
|
||||
String getDirectCtorName(ScriptNode n) {
|
||||
|
@ -1324,7 +1323,7 @@ public class Codegen implements Evaluator {
|
|||
|
||||
private List<OptFunctionNode> directCallTargets;
|
||||
ScriptNode[] scriptOrFnNodes;
|
||||
private ObjToIntMap scriptOrFnIndexes;
|
||||
private HashMap<ScriptNode, Integer> scriptOrFnIndexes;
|
||||
|
||||
private String mainMethodClass = DEFAULT_MAIN_METHOD_CLASS;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче