public class BuildFlat {
State state;
Hashtable temptovar;
+ MethodDescriptor currmd;
+ TypeUtil typeutil;
- public BuildFlat(State st) {
+ public BuildFlat(State st, TypeUtil typeutil) {
state=st;
temptovar=new Hashtable();
+ this.typeutil=typeutil;
}
public Hashtable getMap() {
private void flattenTask(TaskDescriptor td) {
BlockNode bn=state.getMethodBody(td);
FlatNode fn=flattenBlockNode(bn).getBegin();
- FlatFlagActionNode ffan=new FlatFlagActionNode();
+ FlatFlagActionNode ffan=new FlatFlagActionNode(FlatFlagActionNode.PRE);
ffan.addNext(fn);
+
FlatMethod fm=new FlatMethod(td, ffan);
for(int i=0;i<td.numParameters();i++) {
- fm.addParameterTemp(getTempforVar(td.getParameter(i)));
+ VarDescriptor paramvd=td.getParameter(i);
+ fm.addParameterTemp(getTempforVar(paramvd));
+ //Don't need to get temps for tag variables
+ //If they are used, this will be done automatically
+ //If they aren't we won't pass them in
}
/* Flatten Vector of Flag Effects */
/* This method transforms a vector of FlagEffects into the FlatFlagActionNode */
private void updateFlagActionNode(FlatFlagActionNode ffan, Vector flags) {
+ if (flags==null) // Do nothing if the flag effects vector is empty
+ return;
+
for(int i=0;i<flags.size();i++) {
FlagEffects fes=(FlagEffects)flags.get(i);
TempDescriptor flagtemp=getTempforVar(fes.getVar());
+ // Process the flags
for(int j=0;j<fes.numEffects();j++) {
FlagEffect fe=fes.getEffect(j);
ffan.addFlagAction(flagtemp, fe.getFlag(), fe.getStatus());
}
+ // Process the tags
+ for(int j=0;j<fes.numTagEffects();j++) {
+ TagEffect te=fes.getTagEffect(j);
+ TempDescriptor tagtemp=getTempforVar(te.getTag());
+
+ ffan.addTagAction(flagtemp, te.getTag().getTag(), tagtemp, te.getStatus());
+ }
}
}
private void flattenClass(ClassDescriptor cn) {
Iterator methodit=cn.getMethods();
while(methodit.hasNext()) {
- MethodDescriptor md=(MethodDescriptor)methodit.next();
- BlockNode bn=state.getMethodBody(md);
- FlatNode fn=flattenBlockNode(bn).getBegin();
- FlatMethod fm=new FlatMethod(md, fn);
- if (!md.isStatic())
- fm.addParameterTemp(getTempforVar(md.getThis()));
- for(int i=0;i<md.numParameters();i++) {
- fm.addParameterTemp(getTempforVar(md.getParameter(i)));
+ currmd=(MethodDescriptor)methodit.next();
+ BlockNode bn=state.getMethodBody(currmd);
+ NodePair np=flattenBlockNode(bn);
+ FlatNode fn=np.getBegin();
+ if (state.THREAD&&currmd.getModifiers().isSynchronized()) {
+ MethodDescriptor memd=(MethodDescriptor)typeutil.getClass("Object").getMethodTable().get("MonitorEnter");
+ TempDescriptor thistd=getTempforVar(currmd.getThis());
+ FlatCall fc=new FlatCall(memd, null, thistd, new TempDescriptor[0]);
+ fc.addNext(fn);
+ fn=fc;
+ if (np.getEnd().kind()!=FKind.FlatReturnNode) {
+ MethodDescriptor memdex=(MethodDescriptor)typeutil.getClass("Object").getMethodTable().get("MonitorExit");
+ FlatCall fcunlock=new FlatCall(memdex, null, thistd, new TempDescriptor[0]);
+ np.getEnd().addNext(fcunlock);
+ }
+ }
+
+ FlatMethod fm=new FlatMethod(currmd, fn);
+ if (!currmd.isStatic())
+ fm.addParameterTemp(getTempforParam(currmd.getThis()));
+ for(int i=0;i<currmd.numParameters();i++) {
+ fm.addParameterTemp(getTempforParam(currmd.getParameter(i)));
}
- System.out.println(fm.printMethod());
- state.addFlatCode(md,fm);
+ state.addFlatCode(currmd,fm);
}
}
FlatNew fn=new FlatNew(td, out_temp);
TempDescriptor[] temps=new TempDescriptor[con.numArgs()];
FlatNode last=fn;
+ if (td.getClassDesc().hasFlags()) {
+ // if (con.getFlagEffects()!=null) {
+ FlatFlagActionNode ffan=new FlatFlagActionNode(FlatFlagActionNode.NEWOBJECT);
+ FlagEffects fes=con.getFlagEffects();
+ TempDescriptor flagtemp=out_temp;
+ if (fes!=null) {
+ for(int j=0;j<fes.numEffects();j++) {
+ FlagEffect fe=fes.getEffect(j);
+ ffan.addFlagAction(flagtemp, fe.getFlag(), fe.getStatus());
+ }
+ for(int j=0;j<fes.numTagEffects();j++) {
+ TagEffect te=fes.getTagEffect(j);
+ TempDescriptor tagtemp=getTempforVar(te.getTag());
+
+ ffan.addTagAction(flagtemp, te.getTag().getTag(), tagtemp, te.getStatus());
+ }
+ } else {
+ ffan.addFlagAction(flagtemp, null, false);
+ }
+ last.addNext(ffan);
+ last=ffan;
+ }
//Build arguments
for(int i=0;i<con.numArgs();i++) {
ExpressionNode en=con.getArg(i);
//Call to constructor
FlatCall fc=new FlatCall(md, null, out_temp, temps);
last.addNext(fc);
- return new NodePair(fn,fc);
+ last=fc;
+ return new NodePair(fn,last);
} else {
FlatNode first=null;
FlatNode last=null;
}
private NodePair flattenAssignmentNode(AssignmentNode an,TempDescriptor out_temp) {
- // Two cases:
+ // Three cases:
// left side is variable
// left side is field
+ // left side is array
Operation base=an.getOperation().getBaseOp();
- TempDescriptor src_tmp=TempDescriptor.tempFactory("src",an.getSrc().getType());
- NodePair np_src=flattenExpressionNode(an.getSrc(),src_tmp);
- FlatNode last=np_src.getEnd();
- if (base!=null) {
- TempDescriptor src_tmp2=TempDescriptor.tempFactory("tmp", an.getDest().getType());
- NodePair np_dst_init=flattenExpressionNode(an.getDest(),src_tmp2);
- last.addNext(np_dst_init.getBegin());
- TempDescriptor dst_tmp=TempDescriptor.tempFactory("dst_tmp",an.getDest().getType());
- FlatOpNode fon=new FlatOpNode(dst_tmp, src_tmp,src_tmp2, base);
- np_dst_init.getEnd().addNext(fon);
- last=fon;
- src_tmp=dst_tmp;
+ boolean pre=base==null||(base.getOp()!=Operation.POSTINC&&base.getOp()!=Operation.POSTDEC);
+
+ if (!pre) {
+ //rewrite the base operation
+ base=base.getOp()==Operation.POSTINC?new Operation(Operation.ADD):new Operation(Operation.SUB);
+ }
+ FlatNode first=null;
+ FlatNode last=null;
+ TempDescriptor src_tmp=an.getSrc()==null?TempDescriptor.tempFactory("srctmp",an.getDest().getType()):TempDescriptor.tempFactory("srctmp",an.getSrc().getType());
+
+ //Get src value
+ if (an.getSrc()!=null) {
+ NodePair np_src=flattenExpressionNode(an.getSrc(),src_tmp);
+ first=np_src.getBegin();
+ last=np_src.getEnd();
+ } else if (!pre) {
+ FlatLiteralNode fln=new FlatLiteralNode(new TypeDescriptor(TypeDescriptor.INT) ,new Integer(1),src_tmp);
+ first=fln;
+ last=fln;
}
if (an.getDest().kind()==Kind.FieldAccessNode) {
+ //We are assigning an object field
+
FieldAccessNode fan=(FieldAccessNode)an.getDest();
ExpressionNode en=fan.getExpression();
TempDescriptor dst_tmp=TempDescriptor.tempFactory("dst",en.getType());
NodePair np_baseexp=flattenExpressionNode(en, dst_tmp);
- last.addNext(np_baseexp.getBegin());
+ if (first==null)
+ first=np_baseexp.getBegin();
+ else
+ last.addNext(np_baseexp.getBegin());
+ last=np_baseexp.getEnd();
+
+ //See if we need to perform an operation
+ if (base!=null) {
+ //If it is a preinc we need to store the initial value
+ TempDescriptor src_tmp2=pre?TempDescriptor.tempFactory("src",an.getDest().getType()):out_temp;
+ TempDescriptor tmp=TempDescriptor.tempFactory("srctmp3",an.getDest().getType());
+
+ FlatFieldNode ffn=new FlatFieldNode(fan.getField(), dst_tmp, src_tmp2);
+ last.addNext(ffn);
+ last=ffn;
+ FlatOpNode fon=new FlatOpNode(tmp, src_tmp2, src_tmp, base);
+ src_tmp=tmp;
+ last.addNext(fon);
+ last=fon;
+ }
+
FlatSetFieldNode fsfn=new FlatSetFieldNode(dst_tmp, fan.getField(), src_tmp);
- np_baseexp.getEnd().addNext(fsfn);
- return new NodePair(np_src.getBegin(), fsfn);
+ last.addNext(fsfn);
+ last=fsfn;
+ if (pre) {
+ FlatOpNode fon2=new FlatOpNode(out_temp, src_tmp, null, new Operation(Operation.ASSIGN));
+ fsfn.addNext(fon2);
+ last=fon2;
+ }
+ return new NodePair(first, last);
} else if (an.getDest().kind()==Kind.ArrayAccessNode) {
+ //We are assigning an array element
+
+
ArrayAccessNode aan=(ArrayAccessNode)an.getDest();
ExpressionNode en=aan.getExpression();
ExpressionNode enindex=aan.getIndex();
TempDescriptor index_tmp=TempDescriptor.tempFactory("index",enindex.getType());
NodePair np_baseexp=flattenExpressionNode(en, dst_tmp);
NodePair np_indexexp=flattenExpressionNode(enindex, index_tmp);
- last.addNext(np_baseexp.getBegin());
+ if (first==null)
+ first=np_baseexp.getBegin();
+ else
+ last.addNext(np_baseexp.getBegin());
np_baseexp.getEnd().addNext(np_indexexp.getBegin());
+ last=np_indexexp.getEnd();
+
+ //See if we need to perform an operation
+ if (base!=null) {
+ //If it is a preinc we need to store the initial value
+ TempDescriptor src_tmp2=pre?TempDescriptor.tempFactory("src",an.getDest().getType()):out_temp;
+ TempDescriptor tmp=TempDescriptor.tempFactory("srctmp3",an.getDest().getType());
+
+ FlatElementNode fen=new FlatElementNode(dst_tmp, index_tmp, src_tmp2);
+ last.addNext(fen);
+ last=fen;
+ FlatOpNode fon=new FlatOpNode(tmp, src_tmp2, src_tmp, base);
+ src_tmp=tmp;
+ last.addNext(fon);
+ last=fon;
+ }
+
+
FlatSetElementNode fsen=new FlatSetElementNode(dst_tmp, index_tmp, src_tmp);
- np_indexexp.getEnd().addNext(fsen);
- return new NodePair(np_src.getBegin(), fsen);
+ last.addNext(fsen);
+ last=fsen;
+ if (pre) {
+ FlatOpNode fon2=new FlatOpNode(out_temp, src_tmp, null, new Operation(Operation.ASSIGN));
+ fsen.addNext(fon2);
+ last=fon2;
+ }
+ return new NodePair(first, last);
} else if (an.getDest().kind()==Kind.NameNode) {
+ //We could be assigning a field or variable
NameNode nn=(NameNode)an.getDest();
if (nn.getExpression()!=null) {
+ //It is a field
FieldAccessNode fan=(FieldAccessNode)nn.getExpression();
ExpressionNode en=fan.getExpression();
TempDescriptor dst_tmp=TempDescriptor.tempFactory("dst",en.getType());
NodePair np_baseexp=flattenExpressionNode(en, dst_tmp);
- last.addNext(np_baseexp.getBegin());
+ if (first==null)
+ first=np_baseexp.getBegin();
+ else
+ last.addNext(np_baseexp.getBegin());
+ last=np_baseexp.getEnd();
+
+ //See if we need to perform an operation
+ if (base!=null) {
+ //If it is a preinc we need to store the initial value
+ TempDescriptor src_tmp2=pre?TempDescriptor.tempFactory("src",an.getDest().getType()):out_temp;
+ TempDescriptor tmp=TempDescriptor.tempFactory("srctmp3",an.getDest().getType());
+
+ FlatFieldNode ffn=new FlatFieldNode(fan.getField(), dst_tmp, src_tmp2);
+ last.addNext(ffn);
+ last=ffn;
+ FlatOpNode fon=new FlatOpNode(tmp, src_tmp2, src_tmp, base);
+ src_tmp=tmp;
+ last.addNext(fon);
+ last=fon;
+ }
+
+
FlatSetFieldNode fsfn=new FlatSetFieldNode(dst_tmp, fan.getField(), src_tmp);
- np_baseexp.getEnd().addNext(fsfn);
- return new NodePair(np_src.getBegin(), fsfn);
+ last.addNext(fsfn);
+ last=fsfn;
+ if (pre) {
+ FlatOpNode fon2=new FlatOpNode(out_temp, src_tmp, null, new Operation(Operation.ASSIGN));
+ fsfn.addNext(fon2);
+ last=fon2;
+ }
+ return new NodePair(first, last);
} else {
if (nn.getField()!=null) {
+ //It is a field
+ //Get src value
+
+ //See if we need to perform an operation
+ if (base!=null) {
+ //If it is a preinc we need to store the initial value
+ TempDescriptor src_tmp2=pre?TempDescriptor.tempFactory("src",an.getDest().getType()):out_temp;
+ TempDescriptor tmp=TempDescriptor.tempFactory("srctmp3",an.getDest().getType());
+
+ FlatFieldNode ffn=new FlatFieldNode(nn.getField(), getTempforVar(nn.getVar()), src_tmp2);
+ if (first==null)
+ first=ffn;
+ else {
+ last.addNext(ffn);
+ }
+ last=ffn;
+ FlatOpNode fon=new FlatOpNode(tmp, src_tmp2, src_tmp, base);
+ src_tmp=tmp;
+ last.addNext(fon);
+ last=fon;
+ }
+
FlatSetFieldNode fsfn=new FlatSetFieldNode(getTempforVar(nn.getVar()), nn.getField(), src_tmp);
- last.addNext(fsfn);
- return new NodePair(np_src.getBegin(), fsfn);
+ if (first==null) {
+ first=fsfn;
+ } else {
+ last.addNext(fsfn);
+ }
+ last=fsfn;
+ if (pre) {
+ FlatOpNode fon2=new FlatOpNode(out_temp, src_tmp, null, new Operation(Operation.ASSIGN));
+ fsfn.addNext(fon2);
+ last=fon2;
+ }
+ return new NodePair(first, last);
} else {
+ //It is a variable
+ //See if we need to perform an operation
+
+ if (base!=null) {
+ //If it is a preinc we need to store the initial value
+ TempDescriptor src_tmp2=getTempforVar(nn.getVar());
+ TempDescriptor tmp=TempDescriptor.tempFactory("srctmp3",an.getDest().getType());
+ if (!pre) {
+ FlatOpNode fon=new FlatOpNode(out_temp, src_tmp2, null, new Operation(Operation.ASSIGN));
+ if (first==null)
+ first=fon;
+ else
+ last.addNext(fon);
+ last=fon;
+ }
+
+ FlatOpNode fon=new FlatOpNode(tmp, src_tmp2, src_tmp, base);
+ if (first==null)
+ first=fon;
+ else
+ last.addNext(fon);
+ src_tmp=tmp;
+ last=fon;
+ }
+
FlatOpNode fon=new FlatOpNode(getTempforVar(nn.getVar()), src_tmp, null, new Operation(Operation.ASSIGN));
last.addNext(fon);
- return new NodePair(np_src.getBegin(),fon);
+ last=fon;
+ if (pre) {
+ FlatOpNode fon2=new FlatOpNode(out_temp, src_tmp, null, new Operation(Operation.ASSIGN));
+ fon.addNext(fon2);
+ last=fon2;
+ }
+ return new NodePair(first, last);
}
}
}
TempDescriptor temp_right=null;
Operation op=on.getOp();
+ /* We've moved this to assignment nodes
+
if (op.getOp()==Operation.POSTINC||
op.getOp()==Operation.POSTDEC||
op.getOp()==Operation.PREINC||
op.getOp()==Operation.PREDEC) {
LiteralNode ln=new LiteralNode("int",new Integer(1));
ln.setType(new TypeDescriptor(TypeDescriptor.INT));
- AssignmentNode an=new AssignmentNode(on.getLeft(),ln,
- new AssignOperation((op.getOp()==Operation.POSTINC||op.getOp()==Operation.PREINC)?AssignOperation.PLUSEQ:AssignOperation.MINUSEQ));
+
+ AssignmentNode an=new AssignmentNode(on.getLeft(),
+ new OpNode(on.getLeft(),ln,
+ new Operation((op.getOp()==Operation.POSTINC||op.getOp()==Operation.PREINC)?Operation.PLUS:Operation.MINUS))
+ );
if (op.getOp()==Operation.POSTINC||
op.getOp()==Operation.POSTDEC) {
+ //Can't do, this could have side effects
NodePair left=flattenExpressionNode(on.getLeft(),out_temp);
NodePair assign=flattenAssignmentNode(an,temp_left);
left.getEnd().addNext(assign.getBegin());
NodePair assign=flattenAssignmentNode(an,out_temp);
return assign;
}
- }
+ } */
NodePair left=flattenExpressionNode(on.getLeft(),temp_left);
NodePair right;
return new NodePair(fn,fn);
}
}
-
- private TempDescriptor getTempforVar(VarDescriptor vd) {
- if (temptovar.containsKey(vd))
- return (TempDescriptor)temptovar.get(vd);
+
+ private NodePair flattenTagDeclarationNode(TagDeclarationNode dn) {
+ TagVarDescriptor tvd=dn.getTagVarDescriptor();
+ TagDescriptor tag=tvd.getTag();
+ TempDescriptor tmp=getTempforVar(tvd);
+ FlatTagDeclaration ftd=new FlatTagDeclaration(tag, tmp);
+ return new NodePair(ftd,ftd);
+ }
+
+ private TempDescriptor getTempforParam(Descriptor d) {
+ if (temptovar.containsKey(d))
+ return (TempDescriptor)temptovar.get(d);
+ else {
+ if (d instanceof VarDescriptor) {
+ VarDescriptor vd=(VarDescriptor)d;
+ TempDescriptor td=TempDescriptor.paramtempFactory(vd.getName(),vd.getType());
+ temptovar.put(vd,td);
+ return td;
+ } else if (d instanceof TagVarDescriptor) {
+ TagVarDescriptor tvd=(TagVarDescriptor)d;
+ TempDescriptor td=TempDescriptor.paramtempFactory(tvd.getName(),tvd.getTag());
+ temptovar.put(tvd,td);
+ return td;
+ } else throw new Error("Unreconized Descriptor");
+ }
+ }
+
+ private TempDescriptor getTempforVar(Descriptor d) {
+ if (temptovar.containsKey(d))
+ return (TempDescriptor)temptovar.get(d);
else {
- TempDescriptor td=TempDescriptor.tempFactory(vd.getName(),vd.getType());
- temptovar.put(vd,td);
- return td;
+ if (d instanceof VarDescriptor) {
+ VarDescriptor vd=(VarDescriptor)d;
+ TempDescriptor td=TempDescriptor.tempFactory(vd.getName(),vd.getType());
+ temptovar.put(vd,td);
+ return td;
+ } else if (d instanceof TagVarDescriptor) {
+ TagVarDescriptor tvd=(TagVarDescriptor)d;
+ TempDescriptor td=TempDescriptor.tempFactory(tvd.getName(),tvd.getTag());
+ temptovar.put(tvd,td);
+ return td;
+ } else throw new Error("Unrecognized Descriptor");
}
}
FlatNode begin=initializer.getBegin();
FlatCondBranch fcb=new FlatCondBranch(cond_temp);
FlatNop nopend=new FlatNop();
+ FlatBackEdge backedge=new FlatBackEdge();
initializer.getEnd().addNext(condition.getBegin());
body.getEnd().addNext(update.getBegin());
- update.getEnd().addNext(condition.getBegin());
+ update.getEnd().addNext(backedge);
+ backedge.addNext(condition.getBegin());
condition.getEnd().addNext(fcb);
fcb.addFalseNext(nopend);
fcb.addTrueNext(body.getBegin());
FlatNode begin=condition.getBegin();
FlatCondBranch fcb=new FlatCondBranch(cond_temp);
FlatNop nopend=new FlatNop();
+ FlatBackEdge backedge=new FlatBackEdge();
+
+ body.getEnd().addNext(backedge);
+ backedge.addNext(condition.getBegin());
- body.getEnd().addNext(condition.getBegin());
condition.getEnd().addNext(fcb);
fcb.addFalseNext(nopend);
fcb.addTrueNext(body.getBegin());
FlatNode begin=body.getBegin();
FlatCondBranch fcb=new FlatCondBranch(cond_temp);
FlatNop nopend=new FlatNop();
+ FlatBackEdge backedge=new FlatBackEdge();
body.getEnd().addNext(condition.getBegin());
condition.getEnd().addNext(fcb);
fcb.addFalseNext(nopend);
- fcb.addTrueNext(body.getBegin());
+ fcb.addTrueNext(backedge);
+ backedge.addNext(body.getBegin());
return new NodePair(begin,nopend);
} else throw new Error();
}
}
FlatReturnNode rnflat=new FlatReturnNode(retval);
+ FlatNode ln=rnflat;
+ if (state.THREAD&&currmd.getModifiers().isSynchronized()) {
+ MethodDescriptor memd=(MethodDescriptor)typeutil.getClass("Object").getMethodTable().get("MonitorExit");
+ TempDescriptor thistd=getTempforVar(currmd.getThis());
+ FlatCall fc=new FlatCall(memd, null, thistd, new TempDescriptor[0]);
+ fc.addNext(rnflat);
+ ln=fc;
+ }
if (cond!=null) {
- cond.getEnd().addNext(rnflat);
+ cond.getEnd().addNext(ln);
return new NodePair(cond.getBegin(),rnflat);
} else
- return new NodePair(rnflat,rnflat);
+ return new NodePair(ln,rnflat);
}
private NodePair flattenTaskExitNode(TaskExitNode ten) {
- FlatTaskExitNode tenflat=new FlatTaskExitNode();
- return new NodePair(tenflat,tenflat);
+ FlatFlagActionNode ffan=new FlatFlagActionNode(FlatFlagActionNode.TASKEXIT);
+ updateFlagActionNode(ffan, ten.getFlagEffects());
+ NodePair fcn=flattenConstraintCheck(ten.getChecks());
+ ffan.addNext(fcn.getBegin());
+ FlatReturnNode rnflat=new FlatReturnNode(null);
+ fcn.getEnd().addNext(rnflat);
+ return new NodePair(ffan, rnflat);
}
+
+ private NodePair flattenConstraintCheck(Vector ccs) {
+ FlatNode begin=new FlatNop();
+ if (ccs==null)
+ return new NodePair(begin,begin);
+ FlatNode last=begin;
+ for(int i=0;i<ccs.size();i++) {
+ ConstraintCheck cc=(ConstraintCheck) ccs.get(i);
+ /* Flatten the arguments */
+ TempDescriptor[] temps=new TempDescriptor[cc.numArgs()];
+ String[] vars=new String[cc.numArgs()];
+ for(int j=0;j<cc.numArgs();j++) {
+ ExpressionNode en=cc.getArg(j);
+ TempDescriptor td=TempDescriptor.tempFactory("arg",en.getType());
+ temps[j]=td;
+ vars[j]=cc.getVar(j);
+ NodePair np=flattenExpressionNode(en, td);
+ last.addNext(np.getBegin());
+ last=np.getEnd();
+ }
+ FlatCheckNode fcn=new FlatCheckNode(cc.getSpec(), vars, temps);
+ last.addNext(fcn);
+ last=fcn;
+ }
+ return new NodePair(begin,last);
+ }
+
private NodePair flattenSubBlockNode(SubBlockNode sbn) {
return flattenBlockNode(sbn.getBlockNode());
}
case Kind.DeclarationNode:
return flattenDeclarationNode((DeclarationNode)bsn);
+
+ case Kind.TagDeclarationNode:
+ return flattenTagDeclarationNode((TagDeclarationNode)bsn);
case Kind.IfStatementNode:
return flattenIfStatementNode((IfStatementNode)bsn);