if (codeGenerationStats != null) {
codeGenerationStats.incrementDirectForeignCalls();
}
// Unpack the basic op into subexpressions
final BasicOpTuple basicOpExpressions = BasicOpTuple.isBasicOp(e);
final ForeignFunctionInfo foreignFunctionInfo = basicOpExpressions.getForeignFunctionInfo();
final ForeignFunctionInfo.JavaKind kind = foreignFunctionInfo.getJavaKind();
JavaExpression returnExpression = null;
Block returnContext = new Block();
if (kind.isMethod()) {
final ForeignFunctionInfo.Invocation invocationInfo = (ForeignFunctionInfo.Invocation)foreignFunctionInfo;
final Method method = (Method)SCJavaDefn.getJavaProxy(invocationInfo);
if (method.getReturnType() == void.class && (scheme != Scheme.R_SCHEME)) {
ExpressionContextPair ecp = genS_C (e, variableContext);
JavaExpression expr = ecp.getJavaExpression();
JavaStatement block = ecp.getContextBlock();
JavaExpression.MethodInvocation eval = createInvocation(expr, EVALUATE, EXECUTION_CONTEXT_VAR);
return new ExpressionContextPair(eval, block);
}
int nJavaArgs = SCJavaDefn.getNArguments(foreignFunctionInfo);
final Class<?> invocationClass = SCJavaDefn.getInvocationClass(invocationInfo);
final JavaTypeName invocationClassName = JavaTypeName.make(invocationClass);
String methodName = method.getName();
int startArg = 0;
Class<?>[] exceptions = method.getExceptionTypes();
for (int i = 0; i < exceptions.length; ++i) {
if (!exceptionHandled(exceptions [i])) {
addExceptionHandler(exceptions[i]);
}
}
if (!LECCMachineConfiguration.generateDirectPrimOpCalls()) {
if (!exceptionHandled(Throwable.class)) {
addExceptionHandler(Throwable.class);
}
}
JavaExpression target;
InvocationType invocationType; // static, virtual, or interface. Can't be special (ie. private method).
if (kind.isStatic()){
target = null;
invocationType = InvocationType.STATIC;
} else {
ExpressionContextPair pair = generateUnboxedForeignFunctionArgument(invocationClassName, basicOpExpressions.getArgument(0), variableContext);
target = pair.getJavaExpression();
invocationType = invocationClass.isInterface() ? InvocationType.INTERFACE : InvocationType.VIRTUAL;
returnContext.addStatement(pair.getContextBlock());
startArg = 1;
}
Class<?>[] argTypes = method.getParameterTypes();
JavaExpression[] args = new JavaExpression[argTypes.length];
JavaTypeName[] argTypeNames = new JavaTypeName[argTypes.length];
for (int i = startArg, j = 0; i < nJavaArgs; ++i, ++j) {
int index = i - startArg;
final JavaTypeName argTypeName = JavaTypeName.make(argTypes[index]);
ExpressionContextPair pair = generateUnboxedForeignFunctionArgument(argTypeName, basicOpExpressions.getArgument(i), variableContext);
args[index] = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
argTypeNames[index] = argTypeName;
}
JavaTypeName returnType = JavaTypeName.make(method.getReturnType());
if (kind.isStatic()) {
returnExpression = new MethodInvocation.Static(invocationClassName, methodName, args, argTypeNames, returnType);
} else {
returnExpression = new MethodInvocation.Instance(target, methodName, invocationClassName, args, argTypeNames, returnType, invocationType);
}
if (boxResult) {
ExpressionContextPair pair = returnTypeToCal(method.getReturnType(), returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind.isField()) {
final ForeignFunctionInfo.Invocation invocationInfo = (ForeignFunctionInfo.Invocation)foreignFunctionInfo;
final Field field = (Field)SCJavaDefn.getJavaProxy(invocationInfo);
JavaTypeName fieldType = JavaTypeName.make(field.getType());
String fieldName = field.getName();
final JavaTypeName invocationClassName = JavaTypeName.make(SCJavaDefn.getInvocationClass(invocationInfo));
if (kind.isStatic()) {
returnExpression = new JavaField.Static(invocationClassName, fieldName, fieldType);
} else {
ExpressionContextPair pair = generateUnboxedForeignFunctionArgument(invocationClassName, basicOpExpressions.getArgument(0), variableContext);
JavaExpression instance = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
returnExpression = new JavaField.Instance(instance, fieldName, fieldType);
}
if (boxResult) {
ExpressionContextPair pair = returnTypeToCal (field.getType(), returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind.isConstructor()) {
final ForeignFunctionInfo.Invocation invocationInfo = (ForeignFunctionInfo.Invocation)foreignFunctionInfo;
Constructor<?> constructor = (Constructor<?>)SCJavaDefn.getJavaProxy(invocationInfo);
int nJavaArgs = SCJavaDefn.getNArguments(foreignFunctionInfo);
Class<?> clazz = constructor.getDeclaringClass();
Class<?>[] argTypes = constructor.getParameterTypes();
Class<?>[] exceptions = constructor.getExceptionTypes();
for (int i = 0; i < exceptions.length; ++i) {
if (!exceptionHandled(exceptions [i])) {
addExceptionHandler(exceptions[i]);
}
}
JavaExpression[] args = new JavaExpression[argTypes.length];
JavaTypeName[] argTypeNames = new JavaTypeName[argTypes.length];
for (int i = 0; i < nJavaArgs; i++) {
final JavaTypeName argTypeName = JavaTypeName.make(argTypes[i]);
ExpressionContextPair pair = generateUnboxedForeignFunctionArgument(argTypeName, basicOpExpressions.getArgument(i), variableContext);
args[i] = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
argTypeNames[i] = argTypeName;
}
returnExpression = new ClassInstanceCreationExpression(JavaTypeName.make(clazz), args, argTypeNames);
if (boxResult) {
ExpressionContextPair pair = returnTypeToCal(constructor.getDeclaringClass(), returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind.isCast()) {
final Class<?> argType = SCJavaDefn.getJavaArgumentType(foreignFunctionInfo, 0);
final Class<?> resultType = SCJavaDefn.getJavaReturnType(foreignFunctionInfo);
final ExpressionContextPair argExprPair = generateUnboxedForeignFunctionArgument(JavaTypeName.make(argType), basicOpExpressions.getArgument(0), variableContext);
final JavaExpression argExpr = argExprPair.getJavaExpression();
returnContext.addStatement(argExprPair.getContextBlock());
if (kind == ForeignFunctionInfo.JavaKind.IDENTITY_CAST ||
kind == ForeignFunctionInfo.JavaKind.WIDENING_REFERENCE_CAST) {
//it is important to do nothing for a widening reference cast (except for evaluating)
//this is because at the JavaTypeName level, where the inheritance hierarchy is not available, it is not possible for
//the bytecode generator to determine if this is truly a widening reference cast i.e. a no-op. Hence we must make
//this optimization at this point.
returnExpression = argExpr;
} else if (kind == ForeignFunctionInfo.JavaKind.NARROWING_PRIMITIVE_CAST ||
kind == ForeignFunctionInfo.JavaKind.WIDENING_PRIMITIVE_CAST ||
kind == ForeignFunctionInfo.JavaKind.NARROWING_REFERENCE_CAST) {
returnExpression = new JavaExpression.CastExpression(JavaTypeName.make(resultType), argExpr);
} else {
throw new CodeGenerationException("Unrecognized foreign function cast kind: " + kind);
}
if (boxResult) {
ExpressionContextPair pair = returnTypeToCal(resultType, returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind.isInstanceOf()) {
final Class<?> argType = SCJavaDefn.getJavaArgumentType(foreignFunctionInfo, 0);
final ForeignFunctionInfo.InstanceOf instanceOfInfo = (ForeignFunctionInfo.InstanceOf)foreignFunctionInfo;
final Class<?> instanceOfType = SCJavaDefn.getInstanceOfType(instanceOfInfo);
final ExpressionContextPair argExprPair = generateUnboxedForeignFunctionArgument(JavaTypeName.make(argType), basicOpExpressions.getArgument(0), variableContext);
final JavaExpression argExpr = argExprPair.getJavaExpression();
returnContext.addStatement(argExprPair.getContextBlock());
returnExpression = new JavaExpression.InstanceOf(argExpr, JavaTypeName.make(instanceOfType));
if (boxResult) {
ExpressionContextPair pair = returnTypeToCal(boolean.class, returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind.isClassLiteral()) {
final ForeignFunctionInfo.ClassLiteral classLiteralInfo = (ForeignFunctionInfo.ClassLiteral)foreignFunctionInfo;
final Class<?> referentType = SCJavaDefn.getReferentType(classLiteralInfo);
returnExpression = new JavaExpression.ClassLiteral(JavaTypeName.make(referentType));
if (boxResult) {
ExpressionContextPair pair = returnTypeToCal(Class.class, returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind.isNullLiteral()) {
returnExpression = JavaExpression.LiteralWrapper.NULL;
if (boxResult) {
final ExpressionContextPair pair = returnTypeToCal(SCJavaDefn.getJavaReturnType(foreignFunctionInfo), returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind.isNullCheck()) {
final ForeignFunctionInfo.NullCheck nullCheckInfo = (ForeignFunctionInfo.NullCheck)foreignFunctionInfo;
final Class<?> argType = SCJavaDefn.getJavaArgumentType(foreignFunctionInfo, 0);
final ExpressionContextPair argExprPair = generateUnboxedForeignFunctionArgument(JavaTypeName.make(argType), basicOpExpressions.getArgument(0), variableContext);
final JavaExpression argExpr = argExprPair.getJavaExpression();
returnContext.addStatement(argExprPair.getContextBlock());
final JavaOperator javaOp = nullCheckInfo.checkIsNull() ? JavaOperator.EQUALS_OBJECT : JavaOperator.NOT_EQUALS_OBJECT;
returnExpression = new JavaExpression.OperatorExpression.Binary(javaOp, argExpr, LiteralWrapper.NULL);
if (boxResult) {
final ExpressionContextPair pair = returnTypeToCal(boolean.class, returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind == ForeignFunctionInfo.JavaKind.NEW_ARRAY) {
//e.g. newString3Array :: Int -> Int -> JString3Array; (for new String[d1][d2][])
//note, this may be less than the dimension of the array e.g. for new String[10][7][] this is 2.
final int nJavaArgs = SCJavaDefn.getNArguments(foreignFunctionInfo);
final Class<?> newArrayType = SCJavaDefn.getJavaReturnType(foreignFunctionInfo);
final JavaExpression[] args = new JavaExpression[nJavaArgs];
final JavaTypeName[] argTypeNames = new JavaTypeName[nJavaArgs];
for (int i = 0; i < nJavaArgs; i++) {
final ExpressionContextPair pair = generateUnboxedForeignFunctionArgument(JavaTypeName.INT, basicOpExpressions.getArgument(i), variableContext);
args[i] = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
argTypeNames[i] = JavaTypeName.INT;
}
returnExpression = new ClassInstanceCreationExpression(JavaTypeName.make(newArrayType), args, argTypeNames);
if (boxResult) {
final ExpressionContextPair pair = returnTypeToCal(newArrayType, returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind == ForeignFunctionInfo.JavaKind.LENGTH_ARRAY) {
final Class<?> argType = SCJavaDefn.getJavaArgumentType(foreignFunctionInfo, 0);
final ExpressionContextPair argExprPair = generateUnboxedForeignFunctionArgument(JavaTypeName.make(argType), basicOpExpressions.getArgument(0), variableContext);
final JavaExpression argExpr = argExprPair.getJavaExpression();
returnContext.addStatement(argExprPair.getContextBlock());
returnExpression = new JavaExpression.ArrayLength(argExpr);
if (boxResult) {
final ExpressionContextPair pair = returnTypeToCal(int.class, returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind == ForeignFunctionInfo.JavaKind.SUBSCRIPT_ARRAY) {
//e.g. subscriptString3Array :: String3Array -> Int -> Int -> StringArray;
//for subscripting using 2 indices a 3-dimensional String array to get a 1-dimensional String array
//note, this may be less than the dimension of the array e.g. for new String[10][7][] this is 2.
final int nJavaArgs = SCJavaDefn.getNArguments(foreignFunctionInfo);
final Class<?> subscriptedArrayType = SCJavaDefn.getJavaReturnType(foreignFunctionInfo);
for (int i = 0; i < nJavaArgs; i++) {
final JavaTypeName argTypeName = JavaTypeName.make(SCJavaDefn.getJavaArgumentType(foreignFunctionInfo, i));
final ExpressionContextPair pair =
generateUnboxedForeignFunctionArgument(argTypeName, basicOpExpressions.getArgument(i), variableContext);
returnContext.addStatement(pair.getContextBlock());
if (i == 0) {
//the initial array expression
returnExpression = pair.getJavaExpression();
} else {
//subscript by the next index
returnExpression = new JavaExpression.ArrayAccess(returnExpression, pair.getJavaExpression());
}
}
if (boxResult) {
final ExpressionContextPair pair = returnTypeToCal(subscriptedArrayType, returnExpression);
returnExpression = pair.getJavaExpression();
returnContext.addStatement(pair.getContextBlock());
}
return new ExpressionContextPair(returnExpression, returnContext);
} else if (kind == ForeignFunctionInfo.JavaKind.UPDATE_ARRAY) {
//e.g. updateString3Array :: String3Array -> Int -> Int -> StringArray -> StringArray;
//for updating using 2 indices a 3-dimensional String array with a 1-dimensional String array
//note, this may be less than the dimension of the array to update
final int nJavaArgs = SCJavaDefn.getNArguments(foreignFunctionInfo);
final Class<?> updatedElementType = SCJavaDefn.getJavaReturnType(foreignFunctionInfo);
for (int i = 0; i < nJavaArgs; i++) {
final JavaTypeName argTypeName = JavaTypeName.make(SCJavaDefn.getJavaArgumentType(foreignFunctionInfo, i));
final ExpressionContextPair pair =
generateUnboxedForeignFunctionArgument(argTypeName, basicOpExpressions.getArgument(i), variableContext);
returnContext.addStatement(pair.getContextBlock());
if (i == 0) {
//the initial array expression