mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-19 09:30:44 +00:00
Fix bug 49286 "try/catch within JavaScript not working as expected"
Also, accept patches from Igor: Subject: Rhino: UintMap optimization Date: Fri, 06 Jul 2001 13:14:49 +0200 From: Igor Bukanov <igor@icesoft.no> Organization: Wind River To: Norris Boyd <nboyd@atg.com> Hi, Norris! Currently omj.Node uses Hashtable to map int property types to objects/integer. In my opinion this is very inefficient: to store single int property it creates 5 objects: one for property Hahstable, 2 Integer wrappers for property/value, array to sore Hahstable slots and Hashtable slot itself. To fix this I added omj.UintMap class that can map non-negative integers to objects or integers and modified omj.Node to use it. The class is a hashtable implementation that uses one int[] and one Object[] arrays to store keys/values and Object[] array is not created if the map contains only integers. To take full advantage of omj.UintMap code has to be modified to use Node.getIntProp/Node.putIntProp to store int properties, but even in this form it is a win. I can provide patches to use Node.getIntProp/Node.putIntProp and UintMap for InterpreterData.itsLineNumberTable if this is OK. Regards, Igor
This commit is contained in:
parent
0cab42e99d
commit
f7a0fa338c
@ -1590,6 +1590,14 @@ public class Context {
|
||||
throw new RuntimeException("Bad feature index: " + featureIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/Set threshold of executed instructions counter that triggers call to
|
||||
* <code>observeInstructionCount()</code>.
|
||||
* When the threshold is zero, instruction counting is disabled,
|
||||
* otherwise each time the run-time executes at least the threshold value
|
||||
* of script instructions, <code>observeInstructionCount()</code> will
|
||||
* be called.
|
||||
*/
|
||||
public int getInstructionObserverThreshold() {
|
||||
return instructionThreshold;
|
||||
}
|
||||
@ -1598,6 +1606,17 @@ public class Context {
|
||||
instructionThreshold = threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow application to monitor counter of executed script instructions
|
||||
* in Context subclasses.
|
||||
* Run-time calls this when instruction counting is enabled and the counter
|
||||
* reaches limit set by <code>setInstructionObserverThreshold()</code>.
|
||||
* The method is useful to observe long running scripts and if necessary
|
||||
* to terminate them.
|
||||
* @param instructionCount amount of script instruction executed since
|
||||
* last call to <code>observeInstructionCount</code>
|
||||
* @throws Error to terminate the script
|
||||
*/
|
||||
protected void observeInstructionCount(int instructionCount) {}
|
||||
|
||||
/********** end of API **********/
|
||||
|
@ -2075,14 +2075,12 @@ public class Interpreter extends LabelTable {
|
||||
stack[++stackTop] = Undefined.instance;
|
||||
break;
|
||||
case TokenStream.THROW :
|
||||
cx.interpreterSecurityDomain = null;
|
||||
result = stack[stackTop];
|
||||
if (result == DBL_MRK)
|
||||
result = doubleWrap(sDbl[stackTop]);
|
||||
--stackTop;
|
||||
throw new JavaScriptException(result);
|
||||
case TokenStream.JTHROW :
|
||||
cx.interpreterSecurityDomain = null;
|
||||
result = stack[stackTop];
|
||||
// No need to check for DBL_MRK: result is Exception
|
||||
--stackTop;
|
||||
@ -2197,6 +2195,8 @@ public class Interpreter extends LabelTable {
|
||||
|
||||
int exceptionType;
|
||||
Object errObj;
|
||||
if (ex instanceof WrappedException)
|
||||
ex = (Exception) ((WrappedException)ex).unwrap();
|
||||
if (ex instanceof EcmaError) {
|
||||
errObj = ((EcmaError)ex).getErrorObject();
|
||||
exceptionType = ECMA;
|
||||
|
@ -102,7 +102,8 @@ class JavaMembers {
|
||||
throw new RuntimeException("unexpected IllegalAccessException "+
|
||||
"accessing Java field");
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new WrappedException(e.getTargetException());
|
||||
throw WrappedException.wrapException(
|
||||
JavaScriptException.wrapException(scope, e));
|
||||
}
|
||||
// Need to wrap the object before we return it.
|
||||
scope = ScriptableObject.getTopLevelScope(scope);
|
||||
@ -183,8 +184,8 @@ class JavaMembers {
|
||||
}
|
||||
|
||||
|
||||
public void put(String name, Object javaObject, Object value,
|
||||
boolean isStatic)
|
||||
public void put(Scriptable scope, String name, Object javaObject,
|
||||
Object value, boolean isStatic)
|
||||
{
|
||||
Hashtable ht = isStatic ? staticMembers : members;
|
||||
Object member = ht.get(name);
|
||||
@ -212,7 +213,8 @@ class JavaMembers {
|
||||
throw new RuntimeException("unexpected IllegalAccessException " +
|
||||
"accessing Java field");
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new WrappedException(e.getTargetException());
|
||||
throw WrappedException.wrapException(
|
||||
JavaScriptException.wrapException(scope, e));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -111,7 +111,7 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
|
||||
}
|
||||
|
||||
public void put(String name, Scriptable start, Object value) {
|
||||
members.put(name, javaObject, value, true);
|
||||
members.put(this, name, javaObject, value, true);
|
||||
}
|
||||
|
||||
public Object[] getIds() {
|
||||
|
@ -103,7 +103,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
// prototype. Since we can't add a property to a Java object,
|
||||
// we modify it in the prototype rather than copy it down.
|
||||
if (prototype == null || members.has(name, false))
|
||||
members.put(name, javaObject, value, false);
|
||||
members.put(this, name, javaObject, value, false);
|
||||
else
|
||||
prototype.put(name, prototype, value);
|
||||
}
|
||||
|
@ -37,8 +37,6 @@
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class implements the root of the intermediate representation.
|
||||
*
|
||||
@ -330,16 +328,32 @@ public class Node implements Cloneable {
|
||||
public Object getProp(int propType) {
|
||||
if (props == null)
|
||||
return null;
|
||||
return props.get(new Integer(propType));
|
||||
return props.getObject(propType);
|
||||
}
|
||||
|
||||
public int getIntProp(int propType, int defaultValue) {
|
||||
if (props == null)
|
||||
return defaultValue;
|
||||
return props.getInt(propType, defaultValue);
|
||||
}
|
||||
|
||||
public int getExistingIntProp(int propType) {
|
||||
return props.getExistingInt(propType);
|
||||
}
|
||||
|
||||
public void putProp(int propType, Object prop) {
|
||||
if (props == null)
|
||||
props = new Hashtable(2);
|
||||
props = new UintMap(2);
|
||||
if (prop == null)
|
||||
props.remove(new Integer(propType));
|
||||
props.remove(propType);
|
||||
else
|
||||
props.put(new Integer(propType), prop);
|
||||
props.put(propType, prop);
|
||||
}
|
||||
|
||||
public void putIntProp(int propType, int prop) {
|
||||
if (props == null)
|
||||
props = new UintMap(2);
|
||||
props.put(propType, prop);
|
||||
}
|
||||
|
||||
public Object getDatum() {
|
||||
@ -394,15 +408,13 @@ public class Node implements Cloneable {
|
||||
if (props == null)
|
||||
return sb.toString();
|
||||
|
||||
Enumeration keys = props.keys();
|
||||
Enumeration elems = props.elements();
|
||||
while (keys.hasMoreElements()) {
|
||||
Integer key = (Integer) keys.nextElement();
|
||||
Object elem = elems.nextElement();
|
||||
int[] keys = props.getKeys();
|
||||
for (int i = 0; i != keys.length; ++i) {
|
||||
int key = keys[i];
|
||||
sb.append(" [");
|
||||
sb.append(propToString(key.intValue()));
|
||||
sb.append(propToString(key));
|
||||
sb.append(": ");
|
||||
switch (key.intValue()) {
|
||||
switch (key) {
|
||||
case FIXUPS_PROP : // can't add this as it recurses
|
||||
sb.append("fixups property");
|
||||
break;
|
||||
@ -416,7 +428,12 @@ public class Node implements Cloneable {
|
||||
sb.append("last use property");
|
||||
break;
|
||||
default :
|
||||
sb.append(elem.toString());
|
||||
if (props.isObjectType(key)) {
|
||||
sb.append(props.getObject(key).toString());
|
||||
}
|
||||
else {
|
||||
sb.append(props.getExistingInt(key));
|
||||
}
|
||||
break;
|
||||
}
|
||||
sb.append(']');
|
||||
@ -463,7 +480,7 @@ public class Node implements Cloneable {
|
||||
protected Node next; // next sibling
|
||||
protected Node first; // first element of a linked list of children
|
||||
protected Node last; // last element of a linked list of children
|
||||
protected Hashtable props;
|
||||
protected UintMap props;
|
||||
protected Object datum; // encapsulated data; depends on type
|
||||
}
|
||||
|
||||
|
@ -676,6 +676,17 @@ public class ScriptRuntime {
|
||||
return jse.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a WrappedException. Unwrap a JavaScriptException and return
|
||||
* the value, otherwise rethrow.
|
||||
*/
|
||||
public static Object unwrapWrappedException(WrappedException we) {
|
||||
Throwable t = we.getWrappedException();
|
||||
if (t instanceof JavaScriptException)
|
||||
return ((JavaScriptException) t).value;
|
||||
throw we;
|
||||
}
|
||||
|
||||
public static Object getProp(Object obj, String id, Scriptable scope) {
|
||||
Scriptable start;
|
||||
if (obj instanceof Scriptable) {
|
||||
|
468
js/rhino/src/org/mozilla/javascript/UintMap.java
Normal file
468
js/rhino/src/org/mozilla/javascript/UintMap.java
Normal file
@ -0,0 +1,468 @@
|
||||
/* -*- 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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
class UintMap {
|
||||
|
||||
// Map implementation via hashtable,
|
||||
// follows "The Art of Computer Programming" by Donald E. Knuth
|
||||
|
||||
public UintMap() {
|
||||
this(4);
|
||||
}
|
||||
|
||||
public UintMap(int initialCapacity) {
|
||||
if (checkWorld) check(initialCapacity >= 0);
|
||||
// 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) { }
|
||||
minimalPower = i;
|
||||
if (checkSelf) check(minimalPower >= 2);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return keyCount == 0;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return keyCount;
|
||||
}
|
||||
|
||||
public boolean has(int key) {
|
||||
if (checkWorld) check(key >= 0);
|
||||
return 0 <= findIndex(key);
|
||||
}
|
||||
|
||||
public boolean isObjectType(int key) {
|
||||
if (checkWorld) check(key >= 0);
|
||||
int index = findIndex(key);
|
||||
return index >= 0 && isObjectTypeValue(index);
|
||||
}
|
||||
|
||||
public boolean isIntType(int key) {
|
||||
if (checkWorld) check(key >= 0);
|
||||
int index = findIndex(key);
|
||||
return index >= 0 && !isObjectTypeValue(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object value assigned with key.
|
||||
* @return key object value or null if key is absent or does
|
||||
* not have object value
|
||||
*/
|
||||
public Object getObject(int key) {
|
||||
if (checkWorld) check(key >= 0);
|
||||
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 or does
|
||||
* not have int value
|
||||
*/
|
||||
public int getInt(int key, int defaultValue) {
|
||||
if (checkWorld) check(key >= 0);
|
||||
if (ivaluesShift != 0) {
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
if (!isObjectTypeValue(index)) {
|
||||
return keys[ivaluesShift + 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 getExistingInt(int key) {
|
||||
if (checkWorld) check(key >= 0);
|
||||
if (ivaluesShift != 0) {
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
if (!isObjectTypeValue(index)) {
|
||||
return keys[ivaluesShift + index];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Key must exist
|
||||
if (checkWorld) check(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void put(int key, Object value) {
|
||||
if (checkWorld) check(key >= 0 && value != null);
|
||||
int index = ensureIndex(key, false);
|
||||
if (values == null) {
|
||||
values = new Object[1 << power];
|
||||
}
|
||||
values[index] = value;
|
||||
}
|
||||
|
||||
public void put(int key, int value) {
|
||||
if (checkWorld) check(key >= 0);
|
||||
int index = ensureIndex(key, true);
|
||||
if (ivaluesShift == 0) {
|
||||
int N = 1 << power;
|
||||
int[] tmp = new int[N * 2];
|
||||
System.arraycopy(keys, 0, tmp, 0, N);
|
||||
keys = tmp;
|
||||
ivaluesShift = N;
|
||||
}
|
||||
keys[ivaluesShift + index] = value;
|
||||
if (values != null) { values[index] = null; }
|
||||
}
|
||||
|
||||
public void remove(int key) {
|
||||
if (checkWorld) check(key >= 0);
|
||||
int index = findIndex(key);
|
||||
if (0 <= index) {
|
||||
keys[index] = DELETED;
|
||||
--keyCount;
|
||||
if (values != null) { values[index] = null; }
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
power = 0;
|
||||
keys = null;
|
||||
values = 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;
|
||||
}
|
||||
else {
|
||||
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 (checkSelf) check(n++ < occupiedCount);
|
||||
index = (index + step) & mask;
|
||||
entry = keys[index];
|
||||
if (entry == key) { return index; }
|
||||
} while (entry != EMPTY);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int getFreeIndex(int key) {
|
||||
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 (checkSelf) check(keys[index] != DELETED);
|
||||
index = (index + step) & mask;
|
||||
if (checkSelf) check(firstIndex != index);
|
||||
} while (keys[index] != EMPTY);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private void rehashTable(boolean ensureIntSpace) {
|
||||
if (keys == null) { power = minimalPower; }
|
||||
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;
|
||||
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]; }
|
||||
|
||||
if (old != null) {
|
||||
for (int i = 0, remaining = keyCount; remaining != 0; ++i) {
|
||||
int entry = old[i];
|
||||
if (entry != EMPTY && entry != DELETED) {
|
||||
int index = getFreeIndex(entry);
|
||||
keys[index] = entry;
|
||||
if (oldValues != null) {
|
||||
values[index] = oldValues[i];
|
||||
}
|
||||
if (oldShift != 0) {
|
||||
keys[ivaluesShift + index] = old[oldShift + i];
|
||||
}
|
||||
--remaining;
|
||||
}
|
||||
}
|
||||
}
|
||||
occupiedCount = keyCount;
|
||||
}
|
||||
|
||||
// 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 (checkSelf) check(n++ < occupiedCount);
|
||||
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 (checkSelf) check(keys == null || keys[index] == EMPTY);
|
||||
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);
|
||||
keys = this.keys;
|
||||
index = getFreeIndex(key);
|
||||
}
|
||||
++occupiedCount;
|
||||
}
|
||||
keys[index] = key;
|
||||
++keyCount;
|
||||
return index;
|
||||
}
|
||||
|
||||
private boolean isObjectTypeValue(int index) {
|
||||
if (checkSelf) check(index >= 0 && index < (1 << power));
|
||||
return values != null && values[index] != null;
|
||||
}
|
||||
|
||||
private static void check(boolean condition) {
|
||||
if (!condition) { throw new RuntimeException(); }
|
||||
}
|
||||
|
||||
// Rudimentary support for Design-by-Contract
|
||||
private static final boolean checkWorld = true;
|
||||
private static final boolean checkSelf = checkWorld && false;
|
||||
|
||||
// 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 int[] keys;
|
||||
private Object[] values;
|
||||
|
||||
private int minimalPower;
|
||||
private int power;
|
||||
private int keyCount;
|
||||
private int occupiedCount; // == keyCount + deleted_count
|
||||
|
||||
// If ivaluesShift != 0, keys[ivaluesShift + index] contains integer
|
||||
// values associated with keys
|
||||
private int ivaluesShift;
|
||||
|
||||
/*
|
||||
public static void main(String[] args) {
|
||||
UintMap map;
|
||||
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, new Integer(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, new Integer(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.println(); System.out.flush();
|
||||
}
|
||||
//*/
|
||||
}
|
@ -2184,44 +2184,29 @@ public class Codegen extends Interpreter {
|
||||
int realEnd = acquireLabel();
|
||||
addByteCode(ByteCode.GOTO, realEnd);
|
||||
|
||||
|
||||
// javascript handler; unwrap exception and GOTO to javascript
|
||||
// catch area.
|
||||
if (catchTarget != null) {
|
||||
int jsHandler = classFile.markHandler(acquireLabel());
|
||||
|
||||
// MS JVM gets cranky if the exception object is left on the stack
|
||||
short exceptionObject = getNewWordLocal();
|
||||
astore(exceptionObject);
|
||||
|
||||
// reset the variable object local
|
||||
aload(savedVariableObject);
|
||||
astore(variableObjectLocal);
|
||||
|
||||
aload(exceptionObject);
|
||||
releaseWordLocal(exceptionObject);
|
||||
|
||||
// unwrap the exception...
|
||||
addScriptRuntimeInvoke("unwrapJavaScriptException",
|
||||
"(Lorg/mozilla/javascript/JavaScriptException;)",
|
||||
"Ljava/lang/Object;");
|
||||
|
||||
// get the label to goto
|
||||
int catchLabel =
|
||||
((Integer)catchTarget.getProp(Node.LABEL_PROP)).intValue();
|
||||
addByteCode(ByteCode.GOTO, catchLabel);
|
||||
|
||||
// mark the handler
|
||||
classFile.addExceptionHandler
|
||||
(startLabel, catchLabel, jsHandler,
|
||||
"org/mozilla/javascript/JavaScriptException");
|
||||
|
||||
generateCatchBlock(JAVASCRIPTEXCEPTION, savedVariableObject,
|
||||
catchLabel, startLabel);
|
||||
/*
|
||||
* catch WrappedExceptions, see if they are wrapped
|
||||
* JavaScriptExceptions. Otherwise, rethrow.
|
||||
*/
|
||||
generateCatchBlock(WRAPPEDEXCEPTION, savedVariableObject,
|
||||
catchLabel, startLabel);
|
||||
|
||||
/*
|
||||
we also need to catch EcmaErrors and feed the
|
||||
associated error object to the handler
|
||||
*/
|
||||
jsHandler = classFile.markHandler(acquireLabel());
|
||||
exceptionObject = getNewWordLocal();
|
||||
int jsHandler = classFile.markHandler(acquireLabel());
|
||||
short exceptionObject = getNewWordLocal();
|
||||
astore(exceptionObject);
|
||||
aload(savedVariableObject);
|
||||
astore(variableObjectLocal);
|
||||
@ -2268,6 +2253,51 @@ public class Codegen extends Interpreter {
|
||||
markLabel(realEnd);
|
||||
}
|
||||
|
||||
private final int JAVASCRIPTEXCEPTION = 0;
|
||||
private final int WRAPPEDEXCEPTION = 1;
|
||||
|
||||
private void generateCatchBlock(int exceptionType,
|
||||
short savedVariableObject,
|
||||
int catchLabel,
|
||||
int startLabel)
|
||||
{
|
||||
int handler = classFile.markHandler(acquireLabel());
|
||||
|
||||
// MS JVM gets cranky if the exception object is left on the stack
|
||||
short exceptionObject = getNewWordLocal();
|
||||
astore(exceptionObject);
|
||||
|
||||
// reset the variable object local
|
||||
aload(savedVariableObject);
|
||||
astore(variableObjectLocal);
|
||||
|
||||
aload(exceptionObject);
|
||||
releaseWordLocal(exceptionObject);
|
||||
|
||||
if (exceptionType == JAVASCRIPTEXCEPTION) {
|
||||
// unwrap the exception...
|
||||
addScriptRuntimeInvoke("unwrapJavaScriptException",
|
||||
"(Lorg/mozilla/javascript/JavaScriptException;)",
|
||||
"Ljava/lang/Object;");
|
||||
} else {
|
||||
// unwrap the exception...
|
||||
addScriptRuntimeInvoke("unwrapWrappedException",
|
||||
"(Lorg/mozilla/javascript/WrappedException;)",
|
||||
"Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
|
||||
String exceptionName = exceptionType == JAVASCRIPTEXCEPTION
|
||||
? "org/mozilla/javascript/JavaScriptException"
|
||||
: "org/mozilla/javascript/WrappedException";
|
||||
|
||||
// mark the handler
|
||||
classFile.addExceptionHandler(startLabel, catchLabel, handler,
|
||||
exceptionName);
|
||||
|
||||
addByteCode(ByteCode.GOTO, catchLabel);
|
||||
}
|
||||
|
||||
private void visitThrow(Node node, Node child) {
|
||||
visitStatement(node);
|
||||
while (child != null) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user