diff --git a/js/rhino/src/org/mozilla/javascript/Context.java b/js/rhino/src/org/mozilla/javascript/Context.java
index e33ee6a0c82c..911706e2e6a8 100644
--- a/js/rhino/src/org/mozilla/javascript/Context.java
+++ b/js/rhino/src/org/mozilla/javascript/Context.java
@@ -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
+ * observeInstructionCount()
.
+ * When the threshold is zero, instruction counting is disabled,
+ * otherwise each time the run-time executes at least the threshold value
+ * of script instructions, observeInstructionCount()
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 setInstructionObserverThreshold()
.
+ * 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 observeInstructionCount
+ * @throws Error to terminate the script
+ */
protected void observeInstructionCount(int instructionCount) {}
/********** end of API **********/
diff --git a/js/rhino/src/org/mozilla/javascript/Interpreter.java b/js/rhino/src/org/mozilla/javascript/Interpreter.java
index 7e5c67806cfe..c2ae353fa820 100644
--- a/js/rhino/src/org/mozilla/javascript/Interpreter.java
+++ b/js/rhino/src/org/mozilla/javascript/Interpreter.java
@@ -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;
diff --git a/js/rhino/src/org/mozilla/javascript/JavaMembers.java b/js/rhino/src/org/mozilla/javascript/JavaMembers.java
index 49bfdf4adffc..9217371fb571 100644
--- a/js/rhino/src/org/mozilla/javascript/JavaMembers.java
+++ b/js/rhino/src/org/mozilla/javascript/JavaMembers.java
@@ -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 {
diff --git a/js/rhino/src/org/mozilla/javascript/NativeJavaClass.java b/js/rhino/src/org/mozilla/javascript/NativeJavaClass.java
index ac6039a3a05f..73206de1cead 100644
--- a/js/rhino/src/org/mozilla/javascript/NativeJavaClass.java
+++ b/js/rhino/src/org/mozilla/javascript/NativeJavaClass.java
@@ -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() {
diff --git a/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java b/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java
index 1d910b20e862..7b6a517d249e 100644
--- a/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java
+++ b/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java
@@ -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);
}
diff --git a/js/rhino/src/org/mozilla/javascript/Node.java b/js/rhino/src/org/mozilla/javascript/Node.java
index 78424c8e00a5..b3a18f33234e 100644
--- a/js/rhino/src/org/mozilla/javascript/Node.java
+++ b/js/rhino/src/org/mozilla/javascript/Node.java
@@ -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
}
diff --git a/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java b/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java
index f54de2557c75..38f3db2c71cb 100644
--- a/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java
+++ b/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java
@@ -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) {
diff --git a/js/rhino/src/org/mozilla/javascript/UintMap.java b/js/rhino/src/org/mozilla/javascript/UintMap.java
new file mode 100644
index 000000000000..1a987a933c5a
--- /dev/null
+++ b/js/rhino/src/org/mozilla/javascript/UintMap.java
@@ -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();
+ }
+//*/
+}
diff --git a/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java b/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java
index d7f8fbb029ab..4d26d7f10449 100644
--- a/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java
+++ b/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java
@@ -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) {