зеркало из https://github.com/mozilla/gecko-dev.git
ObjToIntMap was added to map Objects to int in a memory wise way and VariableTable was modified to use ObjToIntMap for itsVariableNames
This commit is contained in:
Родитель
73da3c3144
Коммит
e6d6980a29
|
@ -0,0 +1,567 @@
|
|||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Rhino code, released
|
||||
* May 6, 1999.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
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
|
||||
*
|
||||
*/
|
||||
|
||||
public class ObjToIntMap implements Serializable {
|
||||
|
||||
// static final long serialVersionUID = -55740507849272970L;
|
||||
|
||||
// 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;
|
||||
cursor = -1;
|
||||
}
|
||||
|
||||
void init(Object[] keys, int[] values) {
|
||||
this.keys = keys;
|
||||
this.values = values;
|
||||
this.cursor = (keys == null) ? 0 : keys.length;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
master.initIterator(this);
|
||||
next();
|
||||
}
|
||||
|
||||
public boolean done() {
|
||||
return cursor < 0;
|
||||
}
|
||||
|
||||
public void next() {
|
||||
if (cursor < 0) Context.codeBug();
|
||||
--cursor;
|
||||
while (cursor >= 0) {
|
||||
Object key = keys[cursor];
|
||||
if (key != null && key != DELETED) {
|
||||
break;
|
||||
}
|
||||
--cursor;
|
||||
}
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
return keys[cursor];
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return values[cursor];
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
values[cursor] = value;
|
||||
}
|
||||
|
||||
ObjToIntMap master;
|
||||
private int cursor;
|
||||
private Object[] keys;
|
||||
private int[] values;
|
||||
}
|
||||
|
||||
public ObjToIntMap() {
|
||||
this(4);
|
||||
}
|
||||
|
||||
public ObjToIntMap(int keyCountHint) {
|
||||
if (keyCountHint < 0) Context.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) Context.codeBug();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return keyCount == 0;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return keyCount;
|
||||
}
|
||||
|
||||
public boolean has(Object key) {
|
||||
return 0 <= findIndex(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get integer value assigned with key.
|
||||
* @return key integer value or defaultValue if key is absent or does
|
||||
* not have int value
|
||||
*/
|
||||
public int get(Object key, int defaultValue) {
|
||||
if (key == null) Context.codeBug();
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
return values[index];
|
||||
}
|
||||
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 or does
|
||||
* not have int value
|
||||
*/
|
||||
public int getExisting(Object key) {
|
||||
if (key == null) Context.codeBug();
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
return values[index];
|
||||
}
|
||||
// Key must exist
|
||||
Context.codeBug();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void put(Object key, int value) {
|
||||
if (key == null) Context.codeBug();
|
||||
int index = ensureIndex(key);
|
||||
values[index] = value;
|
||||
}
|
||||
|
||||
public void remove(Object key) {
|
||||
if (key == null) Context.codeBug();
|
||||
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);
|
||||
}
|
||||
|
||||
void initIterator(Iterator i) {
|
||||
i.init(keys, values);
|
||||
}
|
||||
|
||||
/** Return array of present keys */
|
||||
public Object[] getKeys() {
|
||||
Object[] keys = this.keys;
|
||||
int count = keyCount;
|
||||
Object[] result = new Object[count];
|
||||
for (int i = 0; count != 0; ++i) {
|
||||
Object key = keys[i];
|
||||
if (key != null && key != DELETED) {
|
||||
result[--count] = key;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
else {
|
||||
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) Context.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;
|
||||
}
|
||||
|
||||
private int getFreeIndex(Object key, int hash) {
|
||||
int fraction = hash * A;
|
||||
int index = fraction >>> (32 - power);
|
||||
if (keys[index] != null) {
|
||||
int mask = (1 << power) - 1;
|
||||
int step = tableLookupStep(fraction, mask, power);
|
||||
int firstIndex = index;
|
||||
do {
|
||||
if (check && keys[index] == DELETED) Context.codeBug();
|
||||
index = (index + step) & mask;
|
||||
if (check && firstIndex == index) Context.codeBug();
|
||||
} while (keys[index] != null);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private void rehashTable() {
|
||||
if (keys == null) {
|
||||
if (check && keyCount != 0) Context.codeBug();
|
||||
if (check && occupiedCount != 0) Context.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];
|
||||
|
||||
for (int i = 0, remaining = keyCount; remaining != 0; ++i) {
|
||||
Object key = oldKeys[i];
|
||||
if (key != null && key != DELETED) {
|
||||
int keyHash = oldValues[oldN + i];
|
||||
int index = getFreeIndex(key, keyHash);
|
||||
keys[index] = key;
|
||||
values[index] = oldValues[i];
|
||||
values[N + index] = keyHash;
|
||||
--remaining;
|
||||
}
|
||||
}
|
||||
occupiedCount = keyCount;
|
||||
}
|
||||
}
|
||||
|
||||
// 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) Context.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)
|
||||
Context.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();
|
||||
index = getFreeIndex(key, hash);
|
||||
}
|
||||
++occupiedCount;
|
||||
}
|
||||
keys[index] = key;
|
||||
values[(1 << power) + index] = hash;
|
||||
++keyCount;
|
||||
return index;
|
||||
}
|
||||
|
||||
// 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 Object[] keys;
|
||||
private int[] values;
|
||||
|
||||
private int power;
|
||||
private int keyCount;
|
||||
private int occupiedCount; // == keyCount + deleted_count
|
||||
|
||||
// If true, enables consitency checks
|
||||
private static final boolean check = false;
|
||||
|
||||
/*
|
||||
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.println(); System.out.flush();
|
||||
}
|
||||
|
||||
private static void check(boolean condition) {
|
||||
if (!condition) Context.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 = new Double(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;
|
||||
}
|
||||
|
||||
|
||||
//*/
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Roger Lawrence
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
|
@ -58,19 +59,15 @@ public class VariableTable {
|
|||
}
|
||||
|
||||
public LocalVariable getVariable(String name) {
|
||||
Integer vIndex = (Integer)(itsVariableNames.get(name));
|
||||
if (vIndex != null)
|
||||
return (LocalVariable)(itsVariables.elementAt(vIndex.intValue()));
|
||||
int vIndex = itsVariableNames.get(name, -1);
|
||||
if (vIndex != -1)
|
||||
return (LocalVariable)(itsVariables.elementAt(vIndex));
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getOrdinal(String name) {
|
||||
Integer vIndex = (Integer)(itsVariableNames.get(name));
|
||||
if (vIndex != null)
|
||||
return vIndex.intValue();
|
||||
else
|
||||
return -1;
|
||||
return itsVariableNames.get(name, -1);
|
||||
}
|
||||
|
||||
public String getName(int index) {
|
||||
|
@ -97,53 +94,48 @@ public class VariableTable {
|
|||
}
|
||||
|
||||
public void addParameter(String pName) {
|
||||
Integer pIndex = (Integer)(itsVariableNames.get(pName));
|
||||
if (pIndex != null) {
|
||||
LocalVariable p = (LocalVariable)
|
||||
(itsVariables.elementAt(pIndex.intValue()));
|
||||
int pIndex = itsVariableNames.get(pName, -1);
|
||||
if (pIndex != -1) {
|
||||
LocalVariable p = (LocalVariable)(itsVariables.elementAt(pIndex));
|
||||
if (p.isParameter()) {
|
||||
String message = Context.getMessage1("msg.dup.parms", pName);
|
||||
Context.reportWarning(message, null, 0, null, 0);
|
||||
}
|
||||
else { // there's a local variable with this name, blow it off
|
||||
itsVariables.removeElementAt(pIndex.intValue());
|
||||
itsVariables.removeElementAt(pIndex);
|
||||
}
|
||||
}
|
||||
int curIndex = varStart++;
|
||||
LocalVariable lVar = createLocalVariable(pName, true);
|
||||
itsVariables.insertElementAt(lVar, curIndex);
|
||||
itsVariableNames.put(pName, new Integer(curIndex));
|
||||
itsVariableNames.put(pName, curIndex);
|
||||
}
|
||||
|
||||
public void addLocal(String vName) {
|
||||
Integer vIndex = (Integer)(itsVariableNames.get(vName));
|
||||
if (vIndex != null) {
|
||||
int vIndex = itsVariableNames.get(vName, -1);
|
||||
if (vIndex != -1) {
|
||||
// There's already a variable or parameter with this name.
|
||||
return;
|
||||
}
|
||||
int index = itsVariables.size();
|
||||
LocalVariable lVar = createLocalVariable(vName, false);
|
||||
itsVariables.addElement(lVar);
|
||||
itsVariableNames.put(vName, new Integer(index));
|
||||
itsVariableNames.put(vName, index);
|
||||
}
|
||||
|
||||
// This should only be called very early in compilation
|
||||
public void removeLocal(String name) {
|
||||
Integer i = (Integer) itsVariableNames.get(name);
|
||||
if (i != null) {
|
||||
itsVariables.removeElementAt(i.intValue());
|
||||
int i = itsVariableNames.get(name, -1);
|
||||
if (i != -1) {
|
||||
itsVariables.removeElementAt(i);
|
||||
itsVariableNames.remove(name);
|
||||
Hashtable ht = new Hashtable(11);
|
||||
Enumeration e = itsVariableNames.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
Object k = e.nextElement();
|
||||
Integer v = (Integer) itsVariableNames.get(k);
|
||||
int v2 = v.intValue();
|
||||
if (v2 > i.intValue())
|
||||
v = new Integer(v2 - 1);
|
||||
ht.put(k, v);
|
||||
ObjToIntMap.Iterator iter = itsVariableNames.newIterator();
|
||||
for (iter.start(); !iter.done(); iter.next()) {
|
||||
int v = iter.getValue();
|
||||
if (v > i) {
|
||||
iter.setValue(v - 1);
|
||||
}
|
||||
}
|
||||
itsVariableNames = ht;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,7 +143,7 @@ public class VariableTable {
|
|||
protected Vector itsVariables = new Vector();
|
||||
|
||||
// mapping from name to index in list
|
||||
protected Hashtable itsVariableNames = new Hashtable(11);
|
||||
private ObjToIntMap itsVariableNames = new ObjToIntMap(11);
|
||||
|
||||
protected int varStart; // index in list of first variable
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче