refactoring of CAst front end machinery to allow more reuse

This commit is contained in:
Julian Dolby 2018-01-25 14:42:27 -05:00
parent 8796653292
commit cd944a8f12
16 changed files with 265 additions and 186 deletions

View File

@ -11,3 +11,4 @@ javacProjectSettings = true
bin.excludes = dat/core-modules/.eslintrc,\
dat/core-modules/.gitignore,\
dat/core-modules/.gitkeep
javacDefaultEncoding.. = UTF-8

View File

@ -38,15 +38,15 @@ public class FieldBasedCGGamesTest extends AbstractFieldBasedTest {
runTestExceptOnTravis(new URL("http://www.inmensia.com/files/solitaire1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC);
}
@Test(expected = CancelException.class)
@Test // (expected = CancelException.class)
public void testWorldOfSolitaire() throws IOException, WalaException, Error, CancelException {
runTestExceptOnTravis(new URL("http://worldofsolitaire.com/"), new Object[][]{}, BuilderType.OPTIMISTIC);
if (System.getenv("TRAVIS") != null) {
// fake it
throw new CancelException(null);
// throw new CancelException(null);
}
}
@Test
public void testMinesweeper() throws IOException, WalaException, Error, CancelException {
runTestExceptOnTravis(new URL("http://www.inmensia.com/files/minesweeper1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);

View File

@ -15,8 +15,8 @@ compilers.p.discouraged-class=0
compilers.p.internal=0
compilers.p.missing-packages=0
compilers.p.missing-version-export-package=2
compilers.p.missing-version-import-package=0
compilers.p.missing-version-require-bundle=0
compilers.p.missing-version-import-package=2
compilers.p.missing-version-require-bundle=2
compilers.p.no-required-att=0
compilers.p.not-externalized-att=0
compilers.p.unknown-attribute=0

View File

@ -4,9 +4,10 @@ Bundle-Name: %Bundle-Name
Bundle-SymbolicName: com.ibm.wala.cast.js.rhino
Bundle-Version: 1.4.4.qualifier
Bundle-Vendor: %Bundle-Vendor
Require-Bundle: com.ibm.wala.cast;bundle-version="1.0.0",
com.ibm.wala.cast.js;bundle-version="1.0.0",
com.ibm.wala.core;bundle-version="1.1.3"
Require-Bundle: com.ibm.wala.cast;bundle-version="1.4.4",
com.ibm.wala.cast.js;bundle-version="1.4.4",
com.ibm.wala.core;bundle-version="1.4.4",
com.ibm.wala.util;bundle-version="1.4.4"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Export-Package: com.ibm.wala.cast.js.translator,

View File

@ -159,10 +159,9 @@ public class RhinoToAstTranslator implements TranslatorToCAst {
*/
private static class FunctionContext extends JavaScriptTranslatorToCAst.FunctionContext<WalkContext,Node> implements WalkContext {
FunctionContext(WalkContext parent, Node s) {
super(parent, s);
}
}
super(parent, s);
}
}
/**
* context used for top-level script declarations
@ -191,26 +190,41 @@ public class RhinoToAstTranslator implements TranslatorToCAst {
private static class BreakContext extends JavaScriptTranslatorToCAst.BreakContext<WalkContext, Node> implements WalkContext {
@Override
public WalkContext getParent() {
return (WalkContext) super.getParent();
}
BreakContext(WalkContext parent, Node breakTo, String label) {
super(parent, breakTo, label);
}
}
private static class LoopContext extends JavaScriptTranslatorToCAst.LoopContext<WalkContext, Node> implements WalkContext {
private static class LoopContext extends TranslatorToCAst.LoopContext<WalkContext, Node> implements WalkContext {
LoopContext(WalkContext parent, Node breakTo, Node continueTo, String label) {
super(parent, breakTo, continueTo, label);
}
@Override
public WalkContext getParent() {
return (WalkContext) super.getParent();
}
private static class TryCatchContext extends JavaScriptTranslatorToCAst.TryCatchContext<WalkContext, Node> implements WalkContext {
}
private static class TryCatchContext extends TranslatorToCAst.TryCatchContext<WalkContext, Node> implements WalkContext {
TryCatchContext(WalkContext parent, CAstNode catchNode) {
super(parent, catchNode);
}
@Override
public WalkContext getParent() {
return (WalkContext) super.getParent();
}
}
private static String operationReceiverName(int operationIndex) {

View File

@ -12,26 +12,24 @@ package com.ibm.wala.cast.js.translator;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst;
import com.ibm.wala.cast.tree.CAstControlFlowMap;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.impl.CAstControlFlowRecorder;
import com.ibm.wala.cast.tree.impl.CAstSourcePositionRecorder;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.debug.Assertions;
public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
interface WalkContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.WalkContext<C, T> {
String script();
@Override
WalkContext<C, T> getParent();
T top();
default String script() {
return getParent().script();
}
/**
* Add a name declaration to this context. For variables or constants, n
@ -39,22 +37,35 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
* variable (if any) may occur in a separate assignment. For functions, n
* should be a {@link CAstNode#FUNCTION_STMT}, including the function body.
*/
void addNameDecl(CAstNode n);
default void addNameDecl(CAstNode n) {
getParent().addNameDecl(n);
}
Collection<CAstNode> getNameDecls();
default Collection<CAstNode> getNameDecls() {
return getParent().getNameDecls();
}
CAstNode getCatchTarget();
default int setOperation(T node) {
return getParent().setOperation(node);
}
int setOperation(T node);
boolean foundMemberOperation(T node);
void copyOperation(T from, T to);
default boolean foundMemberOperation(T node) {
return getParent().foundMemberOperation(node);
}
default void copyOperation(T from, T to) {
getParent().copyOperation(from, to);
}
}
public static class RootContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.RootContext<C, T> implements WalkContext<C,T> {
@Override
public WalkContext<C, T> getParent() {
assert false;
return null;
}
@Override
public String script() { return null; }
@ -98,35 +109,34 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
}
class DelegatingContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.DelegatingContext<C, T> implements WalkContext<C,T> {
public static class FunctionContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.FunctionContext<C, T> implements WalkContext<C,T> {
protected DelegatingContext(C parent) {
super(parent);
private final Vector<CAstNode> initializers = new Vector<>();
@Override
public WalkContext<C, T> getParent() {
return (WalkContext<C, T>) super.getParent();
}
protected FunctionContext(C parent, T s) {
super(parent, s);
}
@Override
public void addNameDecl(CAstNode v) { initializers.add(v); }
@Override
public Collection<CAstNode> getNameDecls() { return initializers; }
@Override
public String script() {
return parent.script();
}
@Override
public T top() {
return parent.top();
}
@Override
public void addNameDecl(CAstNode n) {
parent.addNameDecl(n);
}
@Override
public Collection<CAstNode> getNameDecls() {
return parent.getNameDecls();
}
@Override
public CAstNode getCatchTarget() {
return parent.getCatchTarget();
return CAstControlFlowMap.EXCEPTION_TO_EXIT;
}
@Override
@ -143,51 +153,6 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
public void copyOperation(T from, T to) {
parent.copyOperation(from, to);
}
}
public static class FunctionContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
private final T topNode;
private final CAstSourcePositionRecorder pos = new CAstSourcePositionRecorder();
private final CAstControlFlowRecorder cfg = new CAstControlFlowRecorder(pos);
private final Map<CAstNode, Collection<CAstEntity>> scopedEntities = HashMapFactory.make();
private final Vector<CAstNode> initializers = new Vector<>();
protected FunctionContext(C parent, T s) {
super(parent);
this.topNode = s;
}
@Override
public T top() { return topNode; }
@Override
public CAstNode getCatchTarget() { return CAstControlFlowMap.EXCEPTION_TO_EXIT; }
@Override
public void addScopedEntity(CAstNode construct, CAstEntity e) {
if (! scopedEntities.containsKey(construct)) {
scopedEntities.put(construct, new HashSet<CAstEntity>(1));
}
scopedEntities.get(construct).add(e);
}
@Override
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
return scopedEntities;
}
@Override
public void addNameDecl(CAstNode v) { initializers.add(v); }
@Override
public Collection<CAstNode> getNameDecls() { return initializers; }
@Override
public CAstControlFlowRecorder cfg() { return cfg; }
@Override
public CAstSourcePositionRecorder pos() { return pos; }
}
public static class ScriptContext<C extends WalkContext<C, T>, T> extends FunctionContext<C,T> {
@ -202,48 +167,6 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
public String script() { return script; }
}
public static class TryCatchContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
private final CAstNode catchNode;
protected TryCatchContext(C parent, CAstNode catchNode) {
super(parent);
this.catchNode = catchNode;
}
@Override
public CAstNode getCatchTarget() { return catchNode; }
}
class BreakContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
private final T breakTarget;
protected final String label;
protected BreakContext(C parent, T breakTarget, String label) {
super(parent);
this.breakTarget = breakTarget;
this.label = label;
}
@Override
public T getBreakFor(String l) {
return (l == null || l.equals(label))? breakTarget: super.getBreakFor(l);
}
}
public class LoopContext<C extends WalkContext<C, T>, T> extends BreakContext<C,T> {
private final T continueTo;
protected LoopContext(C parent, T breakTo, T continueTo, String label) {
super(parent, breakTo, label);
this.continueTo = continueTo;
}
@Override
public T getContinueFor(String l) {
return (l == null || l.equals(label))? continueTo: super.getContinueFor(l);
}
}
/**
* Used to determine the value to be passed as the 'this' argument for a
* function call. This is needed since in JavaScript, you can write a call
@ -255,7 +178,8 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
* 'this' parameter in baseVar, and then to use baseVar as the actual argument
* sub-node for the CAst call node
*/
public class MemberDestructuringContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
public class MemberDestructuringContext<C extends WalkContext<C, T>, T> implements WalkContext<C,T> {
private final WalkContext<C, T> parent;
/**
* node for which we actually care about what the base pointer is. this
@ -272,7 +196,7 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
private boolean foundBase = false;
protected MemberDestructuringContext(C parent, T initialBaseFor, int operationIndex) {
super(parent);
this.parent = parent;
baseFor.add( initialBaseFor );
this.operationIndex = operationIndex;
}
@ -296,6 +220,11 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
public void copyOperation(T from, T to) {
if (baseFor.contains(from)) baseFor.add(to);
}
@Override
public WalkContext<C, T> getParent() {
return parent;
}
}
}

View File

@ -16,7 +16,6 @@ package com.ibm.wala.cast.ir.translator;
import com.ibm.wala.cast.tree.CAstControlFlowMap;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.CAstNodeTypeMap;
import com.ibm.wala.cast.tree.CAstSourcePositionMap;
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
import com.ibm.wala.cast.tree.CAstType;
@ -60,7 +59,7 @@ public abstract class AbstractCodeEntity extends AbstractEntity {
}
@Override
public CAstNodeTypeMap getNodeTypeMap() {
public CAstNodeTypeMapRecorder getNodeTypeMap() {
return types;
}

View File

@ -23,7 +23,7 @@ import com.ibm.wala.cast.tree.CAstQualifier;
import com.ibm.wala.cast.tree.CAstType;
import com.ibm.wala.util.debug.Assertions;
class AbstractFieldEntity extends AbstractDataEntity {
public class AbstractFieldEntity extends AbstractDataEntity {
private final String name;
private final Set<CAstQualifier> modifiers;

View File

@ -13,6 +13,7 @@ package com.ibm.wala.cast.ir.translator;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -28,6 +29,7 @@ import com.ibm.wala.cast.tree.rewrite.CAstRewriter.CopyKey;
import com.ibm.wala.cast.tree.rewrite.CAstRewriter.RewriteContext;
import com.ibm.wala.cast.tree.rewrite.CAstRewriterFactory;
import com.ibm.wala.util.WalaException;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.warnings.Warning;
public interface TranslatorToCAst {
@ -48,42 +50,70 @@ public interface TranslatorToCAst {
public interface WalkContext<C extends WalkContext<C, T>, T> {
WalkContext<C, T> getParent();
/**
* get a mapping from CAstNodes to the scoped entities (e.g. functions or
* local classes) introduced by those nodes. Also maps <code>null</code> to
* those entities not corresponding to any node (e.g nested classes)
*/
Map<CAstNode, Collection<CAstEntity>> getScopedEntities();
default Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
return getParent().getScopedEntities();
}
default CAstNode getCatchTarget() {
return getParent().getCatchTarget();
}
default CAstNode getCatchTarget(String s) {
return getParent().getCatchTarget(s);
}
default T top() {
return getParent().top();
}
/**
* associate a child entity with a given CAstNode, e.g. for a function declaration
*/
void addScopedEntity(CAstNode newNode, CAstEntity visit);
default void addScopedEntity(CAstNode newNode, CAstEntity visit) {
getParent().addScopedEntity(newNode, visit);
}
/**
* for recording control-flow relationships among the CAst nodes
*/
CAstControlFlowRecorder cfg();
default CAstControlFlowRecorder cfg() {
return getParent().cfg();
}
/**
* for recording source positions
*/
CAstSourcePositionRecorder pos();
default CAstSourcePositionRecorder pos() {
return getParent().pos();
}
/**
* for recording types of nodes
*/
CAstNodeTypeMapRecorder getNodeTypeMap();
default CAstNodeTypeMapRecorder getNodeTypeMap() {
return getParent().getNodeTypeMap();
}
/**
* for a 'continue' style goto, return the control flow target
*/
T getContinueFor(String label);
default T getContinueFor(String label) {
return getParent().getContinueFor(label);
}
/**
* for a 'break' style goto, return the control flow target
*/
T getBreakFor(String label);
default T getBreakFor(String label) {
return getParent().getBreakFor(label);
}
}
@ -128,6 +158,18 @@ public interface TranslatorToCAst {
assert false;
return null;
}
@Override
public T top() {
assert false;
return null;
}
@Override
public WalkContext<C, T> getParent() {
assert false;
return null;
}
}
@ -139,42 +181,106 @@ public interface TranslatorToCAst {
}
@Override
public CAstControlFlowRecorder cfg() {
return parent.cfg();
public T top() {
return parent.top();
}
@Override
public CAstSourcePositionRecorder pos() {
return parent.pos();
}
@Override
public CAstNodeTypeMapRecorder getNodeTypeMap() {
return parent.getNodeTypeMap();
}
@Override
public T getContinueFor(String label) {
return parent.getContinueFor(label);
}
@Override
public T getBreakFor(String label) {
return parent.getBreakFor(label);
}
@Override
public void addScopedEntity(CAstNode newNode, CAstEntity visit) {
parent.addScopedEntity(newNode, visit);
}
@Override
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
return parent.getScopedEntities();
public WalkContext<C, T> getParent() {
return parent;
}
}
class BreakContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
private final T breakTarget;
protected final String label;
protected BreakContext(C parent, T breakTarget, String label) {
super(parent);
this.breakTarget = breakTarget;
this.label = label;
}
@Override
public T getBreakFor(String l) {
return (l == null || l.equals(label))? breakTarget: super.getBreakFor(l);
}
}
public class LoopContext<C extends WalkContext<C, T>, T> extends BreakContext<C,T> {
private final T continueTo;
protected LoopContext(C parent, T breakTo, T continueTo, String label) {
super(parent, breakTo, label);
this.continueTo = continueTo;
}
@Override
public T getContinueFor(String l) {
return (l == null || l.equals(label))? continueTo: super.getContinueFor(l);
}
}
public static class TryCatchContext<C extends WalkContext<C, T>, T> implements WalkContext<C,T> {
private final Map<String,CAstNode> catchNode;
private final WalkContext<C,T> parent;
protected TryCatchContext(C parent, CAstNode catchNode) {
this(parent, Collections.singletonMap(null, catchNode));
}
protected TryCatchContext(C parent, Map<String,CAstNode> catchNode) {
this.parent = parent;
this.catchNode = catchNode;
}
@Override
public CAstNode getCatchTarget() { return getCatchTarget(null); }
@Override
public CAstNode getCatchTarget(String s) { return catchNode.get(s); }
@Override
public WalkContext<C, T> getParent() {
return parent;
}
}
public static class FunctionContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
private final T topNode;
private final CAstSourcePositionRecorder pos = new CAstSourcePositionRecorder();
private final CAstControlFlowRecorder cfg = new CAstControlFlowRecorder(pos);
private final Map<CAstNode, Collection<CAstEntity>> scopedEntities = HashMapFactory.make();
protected FunctionContext(C parent, T s) {
super(parent);
this.topNode = s;
}
@Override
public T top() { return topNode; }
@Override
public void addScopedEntity(CAstNode construct, CAstEntity e) {
if (! scopedEntities.containsKey(construct)) {
scopedEntities.put(construct, new HashSet<CAstEntity>(1));
}
scopedEntities.get(construct).add(e);
}
@Override
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
return scopedEntities;
}
@Override
public CAstControlFlowRecorder cfg() { return cfg; }
@Override
public CAstSourcePositionRecorder pos() { return pos; }
}
public static class DoLoopTranslator {
private final boolean replicateForDoLoops;

View File

@ -158,9 +158,9 @@ public interface CAstNode {
public static final int IS_DEFINED_EXPR = 128;
public static final int MACRO_VAR = 129;
public static final int NARY_EXPR = 130;
// new nodes with an explicit enclosing argument, e.g. "outer.new Inner()". They are mostly treated the same, except in JavaCAst2IRTranslator.doNewObject
public static final int NEW_ENCLOSING = 131;
public static final int COMPREHENSION_EXPR = 132;
// explicit lexical scopes
public static final int LOCAL_SCOPE = 200;

View File

@ -79,7 +79,9 @@ public class CAstImpl implements CAst {
public int hashCode() {
int code = getKind() * (getChildCount() + 13);
for (int i = 0; i < getChildCount() && i < 15; i++) {
code *= getChild(i).getKind();
if (getChild(i) != null) {
code *= getChild(i).getKind();
}
}
return code;

View File

@ -87,5 +87,7 @@ public class CAstOperator implements CAstNode {
public final static CAstOperator OP_REL_OR = new CAstOperator("||");
public final static CAstOperator OP_BIT_XOR = new CAstOperator("^");
public final static CAstOperator OP_REL_XOR = new CAstOperator("^^");
public final static CAstOperator OP_IN = new CAstOperator("in");
}

View File

@ -330,13 +330,19 @@ public class ShrikeCFG extends AbstractCFG<IInstruction, ShrikeCFG.BasicBlock> i
} else {
TypeReference caughtException = null;
if (element.getCatchClass() != null) {
ClassLoaderReference loader = ShrikeCFG.this.getMethod().getDeclaringClass().getReference().getClassLoader();
ClassLoaderReference loader =
element.getCatchClassLoader() == null?
ShrikeCFG.this.getMethod().getDeclaringClass().getReference().getClassLoader():
(ClassLoaderReference)element.getCatchClassLoader();
caughtException = ShrikeUtil.makeTypeReference(loader, element.getCatchClass());
if (DEBUG) {
//if (DEBUG) {
System.err.println(" caughtException " + caughtException);
}
//}
IClass caughtClass = cha.lookupClass(caughtException);
if (caughtClass == null) {
//if (DEBUG) {
System.err.println(" caughtException class " + caughtClass);
//}
if (caughtClass == null) {
// conservatively add the edge, and raise a warning
addExceptionalEdgeTo(b);
Warnings.add(FailedExceptionResolutionWarning.create(caughtException));

View File

@ -147,7 +147,7 @@ public class ClassHierarchy implements IClassHierarchy {
klass = klass.getSuperclass();
while (klass != null) {
while (klass != null) {
if (DEBUG) {
System.err.println("got superclass " + klass);
}
@ -295,6 +295,7 @@ public class ClassHierarchy implements IClassHierarchy {
*/
@Override
public boolean addClass(IClass klass) {
if (klass == null) {
throw new IllegalArgumentException("klass is null");
}
@ -325,7 +326,7 @@ public class ClassHierarchy implements IClassHierarchy {
if (klass.getReference().equals(this.rootTypeRef)) {
// there is only one root
assert root == null;
assert root == null || root == node;
root = node;
}
@ -342,6 +343,10 @@ public class ClassHierarchy implements IClassHierarchy {
}
supernode.addChild(node);
if (supernode.getJavaClass().getReference().equals(rootTypeRef)) {
assert root == null || root == supernode;
root = supernode;
node = null;
} else {
node = supernode;

View File

@ -30,6 +30,7 @@ import com.ibm.wala.classLoader.IClassLoader;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.shrikeBT.ExceptionHandler;
import com.ibm.wala.shrikeBT.IInstruction;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashMapFactory;
@ -168,6 +169,8 @@ public class SSACFG implements ControlFlowGraph<SSAInstruction, ISSABasicBlock>,
if (handler.getCatchClass() == null) {
// by convention, in ShrikeCT this means catch everything
t = TypeReference.JavaLangThrowable;
} else if (handler.getCatchClassLoader() instanceof ClassLoaderReference) {
t = ShrikeUtil.makeTypeReference((ClassLoaderReference)handler.getCatchClassLoader(), handler.getCatchClass());
} else {
TypeReference exceptionType = ShrikeUtil.makeTypeReference(loader.getReference(), handler.getCatchClass());
IClass klass = null;

View File

@ -34,17 +34,24 @@ final public class ExceptionHandler {
int handler;
final String catchClass;
final Object catchClassLoader;
/**
* @param handler the label for the handler code
* @param catchClass the type of exception that should be caught (in JVM format), or null if all exceptions should be caught (as
* with 'finally')
*/
public ExceptionHandler(int handler, String catchClass) {
public ExceptionHandler(int handler, String catchClass, Object catchClassLoader) {
this.handler = handler;
this.catchClass = catchClass;
this.catchClassLoader = catchClassLoader;
}
public ExceptionHandler(int handler, String catchClass) {
this(handler, catchClass, null);
}
/**
* @return the label of the handler code
*/
@ -52,6 +59,10 @@ final public class ExceptionHandler {
return handler;
}
public Object getCatchClassLoader() {
return catchClassLoader;
}
/**
* @return the type of exceptions to be caught, or null if all exceptions should be caught
*/