/*
* Created on Sep 26, 2005
*/
package x10.wala.translator;
import x10.wala.classLoader.AsyncCallSiteReference;
import x10.wala.loader.X10SourceLoaderImpl;
import x10.wala.ssa.AstX10InstructionFactory;
import x10.wala.translator.X10toCAstTranslator.AsyncEntity;
import x10.wala.translator.X10toCAstTranslator.ClosureBodyEntity;
import x10.wala.translator.X10toCAstTranslator.TypeDeclarationCAstEntity;
import x10.wala.tree.X10CAstEntity;
import x10.wala.tree.X10CastNode;
import x10.wala.tree.visit.X10DelegatingCAstVisitor;
import com.ibm.wala.cast.ir.translator.AstTranslator;
import com.ibm.wala.cast.ir.translator.AstTranslator.WalkContext;
import com.ibm.wala.cast.java.loader.JavaSourceLoaderImpl;
import com.ibm.wala.cast.java.translator.JavaCAst2IRTranslator;
import com.ibm.wala.cast.java.types.JavaPrimitiveTypeMap;
import com.ibm.wala.cast.loader.AstMethod.DebuggingInformation;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.CAstType;
import com.ibm.wala.cast.tree.visit.CAstVisitor;
import com.ibm.wala.cfg.AbstractCFG;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.strings.Atom;
public class X10CAst2IRTranslator extends X10DelegatingCAstVisitor /* implements ArrayOpHandler */ {
private static class X10JavaCAst2IRTranslator extends JavaCAst2IRTranslator {
protected final X10SourceLoaderImpl x10Loader;
private X10JavaCAst2IRTranslator(CAstEntity sourceFileEntity, JavaSourceLoaderImpl loader) {
super(sourceFileEntity, loader);
x10Loader = (X10SourceLoaderImpl) loader;
}
/* (non-Javadoc)
* @see com.ibm.wala.cast.ir.translator.AstTranslator#doLexicallyScopedRead(com.ibm.wala.cast.tree.CAstNode, com.ibm.wala.cast.ir.translator.AstTranslator.WalkContext, java.lang.String)
*
* Ugly hack to allow code in this class to see this protected method, since it is now declared in this
* package in this subclass.
*/
@Override
protected int doLexicallyScopedRead(CAstNode node, WalkContext context, String name) {
return super.doLexicallyScopedRead(node, context, name);
}
@Override
protected void defineFunction(CAstEntity n,
WalkContext definingContext,
AbstractCFG cfg,
SymbolTable symtab,
boolean hasCatchBlock,
TypeReference[][] catchTypes,
boolean hasMonitorOp,
AstLexicalInformation lexicalInfo,
DebuggingInformation debugInfo) {
if (n.getKind() == X10CAstEntity.ASYNC_BODY) {
x10Loader.defineAsync(n,
asyncTypeReference(x10Loader, n),
n.getPosition(), definingContext, cfg, symtab, hasCatchBlock, catchTypes,
hasMonitorOp, lexicalInfo, debugInfo);
} else if (n.getKind() == X10CAstEntity.CLOSURE_BODY) {
x10Loader.defineClosure(n,
closureTypeReference(x10Loader, n),
n.getPosition(), definingContext, cfg, symtab, hasCatchBlock, catchTypes,
hasMonitorOp, lexicalInfo, debugInfo);
} else
super.defineFunction(n, definingContext, cfg, symtab, hasCatchBlock, catchTypes, hasMonitorOp, lexicalInfo, debugInfo);
}
}
public X10CAst2IRTranslator(CAstEntity sourceFileEntity, X10SourceLoaderImpl loader) {
this(new X10JavaCAst2IRTranslator(sourceFileEntity, loader));
}
private final X10JavaCAst2IRTranslator translator;
private final AstX10InstructionFactory insts;
private X10CAst2IRTranslator(X10JavaCAst2IRTranslator translator) {
super(translator);
this.translator = translator;
// this.translator.setArrayOpHandler(this);
this.insts = (AstX10InstructionFactory) translator.loader().getInstructionFactory();
}
protected void leaveFunctionExpr(CAstNode n, Context c, CAstVisitor visitor) {
int result;
CAstEntity fn= (CAstEntity) n.getChild(0).getValue();
if (fn.getKind() == X10CAstEntity.ASYNC_BODY)
result= processAsyncExpr(n, c);
else if (fn.getKind() == X10CAstEntity.CLOSURE_BODY)
result= processClosureExpr(n, c);
else {
Assertions.UNREACHABLE("FUNCTION_EXPR neither async nor closure in leaveFunctionExpr().");
return;
}
translator.setValue(n, result);
}
private int processAsyncExpr(CAstNode n, Context c) {
WalkContext context= (WalkContext) c;
CAstEntity fn= (CAstEntity) n.getChild(0).getValue();
int result= context.currentScope().allocateTempValue();
int ex= context.currentScope().allocateTempValue();
doMaterializeAsync(context, result, ex, fn);
return result;
}
private void doMaterializeAsync(WalkContext context, int result, int ex, CAstEntity fn) {
TypeReference asyncRef= asyncTypeReference(fn);
context.cfg().addInstruction(insts.NewInstruction(result,
NewSiteReference.make(context.cfg().getCurrentInstruction(), asyncRef)));
}
private int processClosureExpr(CAstNode n, Context c) {
WalkContext context= (WalkContext) c;
CAstEntity fn= (CAstEntity) n.getChild(0).getValue();
int result= context.currentScope().allocateTempValue();
int ex= context.currentScope().allocateTempValue();
doMaterializeClosure(context, result, ex, fn);
return result;
}
private void doMaterializeClosure(WalkContext context, int result, int ex, CAstEntity fn) {
TypeReference closureRef= closureTypeReference(fn);
context.cfg().addInstruction(insts.NewInstruction(result,
NewSiteReference.make(context.cfg().getCurrentInstruction(), closureRef)));
}
private static TypeReference asyncTypeReference(JavaSourceLoaderImpl loader, CAstEntity fn) {
return TypeReference.findOrCreate(loader.getReference(), "LA" + fn.getName());
}
private TypeReference asyncTypeReference(CAstEntity fn) {
return asyncTypeReference(translator.loader(), fn);
}
public MethodReference asyncEntityToMethodReference(CAstEntity asyncEntity) {
CAstType.Method bodyType= (CAstType.Method) asyncEntity.getType();
CAstType retType= bodyType.getReturnType();
// CAstType owningType= bodyType.getDeclaringType();
// JavaSourceLoaderImpl fLoader = translator.loader();
Atom asyncName= Atom.findOrCreateUnicodeAtom(asyncEntity.getName());
Descriptor asyncDesc= Descriptor.findOrCreate(null, TypeName.string2TypeName(retType.getName()));
// RMF 1/12/07 - Type ref must agree with what's used when the async type is defined!
// The following commented-out version didn't do that...
// TypeReference owningTypeRef= TypeReference.findOrCreate(fLoader.getReference(), TypeName.string2TypeName(owningType.getName()));
TypeReference owningTypeRef= asyncTypeReference(asyncEntity);
return MethodReference.findOrCreate(owningTypeRef, asyncName, asyncDesc);
}
protected boolean visitAsyncBodyEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) {
translator.initFunctionEntity(n, (WalkContext)context, (WalkContext)codeContext);
return false;
}
protected void leaveAsyncBodyEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) {
translator.closeFunctionEntity(n, (WalkContext)context, (WalkContext)codeContext);
}
protected boolean visitAsyncInvoke(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ return false; }
protected void leaveAsyncInvoke(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
CAstEntity bodyEntity = (CAstEntity) n.getChild(n.getChildCount()-1).getChild(0).getValue();
// Figure out whether this is a future or an async
int exceptValue = context.currentScope().allocateTempValue();
AsyncCallSiteReference acsr = new AsyncCallSiteReference(asyncEntityToMethodReference(bodyEntity), context.cfg().getCurrentInstruction());
int rcvrValue = translator.getValue(n.getChild(n.getChildCount()-1));
int clockValues[] = new int[ n.getChildCount() - 1];
for(int i = 0; i < clockValues.length; i++) {
clockValues[i] = translator.getValue(n.getChild(i));
}
if (((CAstType.Function) bodyEntity.getType()).getReturnType() == JavaPrimitiveTypeMap.VoidType)
context.cfg().addInstruction(insts.AsyncInvoke(new int[] { rcvrValue }, exceptValue, acsr, clockValues));
else {
int retValue = context.currentScope().allocateTempValue();
context.cfg().addInstruction(insts.AsyncInvoke(retValue, new int[] { rcvrValue }, exceptValue, acsr, clockValues));
translator.setValue(n, retValue);
}
}
private static TypeReference closureTypeReference(JavaSourceLoaderImpl loader, CAstEntity fn) {
return TypeReference.findOrCreate(loader.getReference(), "Lclosure" + fn.getPosition());
}
private TypeReference closureTypeReference(CAstEntity fn) {
return closureTypeReference(translator.loader(), fn);
}
protected boolean visitClosureBodyEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) {
translator.initFunctionEntity(n, (WalkContext)context, (WalkContext)codeContext);
return false;
}
protected void leaveClosureBodyEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) {
translator.closeFunctionEntity(n, (WalkContext)context, (WalkContext)codeContext);
}
protected boolean visitAtomicEnter(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ return false; }
protected void leaveAtomicEnter(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
context.cfg().addInstruction(insts.Atomic(true));
}
protected boolean visitAtomicExit(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ return false; }
protected void leaveAtomicExit(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
context.cfg().addInstruction(insts.Atomic(false));
}
protected boolean visitFinishEnter(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ return false; }
protected void leaveFinishEnter(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
context.cfg().addInstruction(insts.Finish(true));
}
protected boolean visitFinishExit(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ return false; }
protected void leaveFinishExit(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
context.cfg().addInstruction(insts.Finish(false));
}
protected boolean visitNext(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
context.cfg().addInstruction(insts.Next());
return true;
}
protected boolean visitIterInit(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ return false; }
protected void leaveIterInit(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
int targetValue = translator.getValue(n.getChild(0));
int retValue = context.currentScope().allocateTempValue();
context.cfg().addInstruction(insts.IterInit(retValue, targetValue));
translator.setValue(n, retValue);
}
protected boolean visitIterHasNext(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ return false; }
protected void leaveIterHasNext(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
int targetValue = translator.getValue(n.getChild(0));
int retValue = context.currentScope().allocateTempValue();
context.cfg().addInstruction(insts.IterHasNext(retValue, targetValue));
translator.setValue(n, retValue);
}
protected boolean visitIterNext(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ return false; }
protected void leaveIterNext(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
int targetValue = translator.getValue(n.getChild(0));
int retValue = context.currentScope().allocateTempValue();
context.cfg().addInstruction(insts.IterNext(retValue, targetValue));
translator.setValue(n, retValue);
}
protected boolean visitHere(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ return false; }
protected void leaveHere(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
int retValue = context.currentScope().allocateTempValue();
context.cfg().addInstruction(insts.Here(retValue));
translator.setValue(n, retValue);
}
protected void leaveThis(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
CAstEntity entity = context.top();
if (entity instanceof AsyncEntity || entity instanceof ClosureBodyEntity) {
translator.setValue(n, translator.doLexicallyScopedRead(n, context, "this"));
} else {
super.leaveThis(n, c, visitor);
}
}
protected boolean visitTupleExpr(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ return false; }
protected void leaveTupleExpr(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
int retValue = context.currentScope().allocateTempValue();
int slotValues[] = new int[n.getChildCount() - 1];
for(int i = 0; i < slotValues.length; i++) {
slotValues[i] = translator.getValue(n.getChild(i+1));
}
context.cfg().addInstruction(insts.Tuple(retValue, slotValues));
translator.setValue(n, retValue);
}
protected boolean visitAtStmtEnter(final CAstNode node, final Context context, final CAstVisitor visitor) {
((WalkContext) context).cfg().addInstruction(insts.AtStmt(true));
return true;
}
protected boolean visitAtStmtExit(final CAstNode node, final Context context, final CAstVisitor visitor) {
((WalkContext) context).cfg().addInstruction(insts.AtStmt(false));
return true;
}
protected boolean visitTypeEntity(final CAstEntity node, final Context context, final Context typeContext,
final CAstVisitor visitor) {
// We avoid type declarations in _.x10 file.
if (node instanceof TypeDeclarationCAstEntity) {
return true;
} else {
return super.visitTypeEntity(node, context, typeContext, visitor);
}
}
private void translate(final CAstEntity N, final String nm) {
if (AstTranslator.DEBUG_TOP)
System.err.println("translating " + nm);
// PrintWriter printWriter= new PrintWriter(System.out);
// X10CAstPrinter.printTo(N, printWriter);
// printWriter.flush();
visitEntities(N, translator.new DefaultContext(translator, N, nm), this);
}
/* UGH! */
public void translate() {
CAstEntity fSourceEntity = translator.sourceFileEntity();
translate(fSourceEntity, fSourceEntity.getName());
}
public JavaCAst2IRTranslator getCAst2IRTranslator() {
return translator;
}
/**
* Returns true if the given array reference operation indexes using an x10.lang.point,
* rather than an array of ints (as in ordinary Java)
*/
private boolean isRefByPoint(CAstNode arrayRefNode) {
return arrayRefNode.getChildCount() > 3 || // if there are multiple indices, it's not by point
arrayRefNode.getKind() == X10CastNode.ARRAY_REF_BY_POINT;
}
/*
public void doArrayRead(WalkContext context, int result, int arrayValue, CAstNode arrayRefNode, int[] dimValues) {
TypeReference arrayTypeRef= (TypeReference) arrayRefNode.getChild(1).getValue();
if (isRefByPoint(arrayRefNode))
context.cfg().addInstruction(
insts.ArrayLoadByPoint(result, arrayValue, dimValues[0], arrayTypeRef));
else
context.cfg().addInstruction(
insts.ArrayLoadByIndex(result, arrayValue, dimValues, arrayTypeRef));
}
public void doArrayWrite(WalkContext context, int arrayValue, CAstNode arrayRefNode, int[] dimValues, int rval) {
TypeReference arrayTypeRef =
arrayRefNode.getKind() == CAstNode.ARRAY_LITERAL ?
((TypeReference) arrayRefNode.getChild(0).getChild(0).getValue()).getArrayElementType() :
(TypeReference) arrayRefNode.getChild(1).getValue();
if (isRefByPoint(arrayRefNode))
context.cfg().addInstruction(
insts.ArrayStoreByPoint(arrayValue, dimValues[0], rval, arrayTypeRef));
else
context.cfg().addInstruction(
insts.ArrayStoreByIndex(arrayValue, dimValues, rval, arrayTypeRef));
}
*/
@Override
protected boolean doVisitAssignNodes(CAstNode n, Context context, CAstNode v, CAstNode a, CAstVisitor visitor) {
int NT = a.getKind();
boolean assign = NT == CAstNode.ASSIGN;
boolean preOp = NT == CAstNode.ASSIGN_PRE_OP;
if (n.getKind() == X10CastNode.ARRAY_REF_BY_POINT) {
doVisitArrayRefNode(n, v, a, assign, preOp, context, visitor);
return true;
} else {
return false;
}
}
}