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:
Greg Brail 2024-08-13 17:57:25 -07:00
Родитель 03a94c3a69
Коммит 04d54698af
17 изменённых файлов: 129 добавлений и 1395 удалений

Просмотреть файл

@ -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;