use of org.codehaus.groovy.classgen.asm.CallSiteWriter in project groovy by apache.
the class StaticInvocationWriter method makeCall.
@Override
public void makeCall(final Expression origin, final Expression receiver, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean safe, final boolean spreadSafe, final boolean implicitThis) {
if (origin.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION) != null) {
StaticTypesWriterController staticController = (StaticTypesWriterController) controller;
if (origin instanceof MethodCallExpression) {
((MethodCallExpression) origin).setMethodTarget(null);
}
InvocationWriter dynamicInvocationWriter = staticController.getRegularInvocationWriter();
dynamicInvocationWriter.makeCall(origin, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
return;
}
if (implicitThis && tryImplicitReceiver(origin, message, arguments, adapter, safe, spreadSafe)) {
return;
}
// if call is spread safe, replace it with a for in loop
if (spreadSafe && origin instanceof MethodCallExpression) {
// receiver expressions with side effects should not be visited twice, avoid by using a temporary variable
Expression tmpReceiver = receiver;
if (!(receiver instanceof VariableExpression) && !(receiver instanceof ConstantExpression)) {
tmpReceiver = new TemporaryVariableExpression(receiver);
}
MethodVisitor mv = controller.getMethodVisitor();
CompileStack compileStack = controller.getCompileStack();
TypeChooser typeChooser = controller.getTypeChooser();
OperandStack operandStack = controller.getOperandStack();
ClassNode classNode = controller.getClassNode();
int counter = labelCounter.incrementAndGet();
// use a temporary variable for the arraylist in which the results of the spread call will be stored
ConstructorCallExpression cce = ctorX(StaticCompilationVisitor.ARRAYLIST_CLASSNODE);
cce.setNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, StaticCompilationVisitor.ARRAYLIST_CONSTRUCTOR);
TemporaryVariableExpression result = new TemporaryVariableExpression(cce);
result.visit(controller.getAcg());
operandStack.pop();
// if (receiver != null)
tmpReceiver.visit(controller.getAcg());
Label ifnull = compileStack.createLocalLabel("ifnull_" + counter);
mv.visitJumpInsn(IFNULL, ifnull);
// receiver consumed by if()
operandStack.remove(1);
Label nonull = compileStack.createLocalLabel("nonull_" + counter);
mv.visitLabel(nonull);
ClassNode componentType = StaticTypeCheckingVisitor.inferLoopElementType(typeChooser.resolveType(tmpReceiver, classNode));
Parameter iterator = new Parameter(componentType, "for$it$" + counter);
VariableExpression iteratorAsVar = varX(iterator);
MethodCallExpression origMCE = (MethodCallExpression) origin;
MethodCallExpression newMCE = callX(iteratorAsVar, origMCE.getMethodAsString(), origMCE.getArguments());
newMCE.setImplicitThis(false);
newMCE.setMethodTarget(origMCE.getMethodTarget());
newMCE.setSafe(true);
MethodCallExpression add = callX(result, "add", newMCE);
add.setImplicitThis(false);
add.setMethodTarget(StaticCompilationVisitor.ARRAYLIST_ADD_METHOD);
// for (e in receiver) { result.add(e?.method(arguments) }
ForStatement stmt = new ForStatement(iterator, tmpReceiver, stmt(add));
stmt.visit(controller.getAcg());
// else { empty list }
mv.visitLabel(ifnull);
// end of if/else
// return result list
result.visit(controller.getAcg());
// cleanup temporary variables
if (tmpReceiver instanceof TemporaryVariableExpression) {
((TemporaryVariableExpression) tmpReceiver).remove(controller);
}
result.remove(controller);
} else if (safe && origin instanceof MethodCallExpression) {
// wrap call in an IFNULL check
MethodVisitor mv = controller.getMethodVisitor();
CompileStack compileStack = controller.getCompileStack();
OperandStack operandStack = controller.getOperandStack();
int counter = labelCounter.incrementAndGet();
// if (receiver != null)
ExpressionAsVariableSlot slot = new ExpressionAsVariableSlot(controller, receiver);
slot.visit(controller.getAcg());
operandStack.box();
Label ifnull = compileStack.createLocalLabel("ifnull_" + counter);
mv.visitJumpInsn(IFNULL, ifnull);
// receiver consumed by if()
operandStack.remove(1);
Label nonull = compileStack.createLocalLabel("nonull_" + counter);
mv.visitLabel(nonull);
MethodCallExpression origMCE = (MethodCallExpression) origin;
MethodCallExpression newMCE = callX(new VariableSlotLoader(slot.getType(), slot.getIndex(), controller.getOperandStack()), origMCE.getMethodAsString(), origMCE.getArguments());
MethodNode methodTarget = origMCE.getMethodTarget();
newMCE.setImplicitThis(origMCE.isImplicitThis());
newMCE.setMethodTarget(methodTarget);
newMCE.setSafe(false);
newMCE.setSourcePosition(origMCE);
newMCE.getObjectExpression().setSourcePosition(origMCE.getObjectExpression());
newMCE.visit(controller.getAcg());
compileStack.removeVar(slot.getIndex());
ClassNode returnType = operandStack.getTopOperand();
if (ClassHelper.isPrimitiveType(returnType) && !isPrimitiveVoid(returnType)) {
operandStack.box();
}
Label endof = compileStack.createLocalLabel("endof_" + counter);
mv.visitJumpInsn(GOTO, endof);
mv.visitLabel(ifnull);
// else { null }
mv.visitInsn(ACONST_NULL);
mv.visitLabel(endof);
} else {
if (origin instanceof AttributeExpression && (adapter == AsmClassGenerator.getField || adapter == AsmClassGenerator.getGroovyObjectField)) {
CallSiteWriter callSiteWriter = controller.getCallSiteWriter();
String fieldName = ((AttributeExpression) origin).getPropertyAsString();
if (fieldName != null && callSiteWriter instanceof StaticTypesCallSiteWriter) {
ClassNode receiverType = controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
if (((StaticTypesCallSiteWriter) callSiteWriter).makeGetField(receiver, receiverType, fieldName, safe, false)) {
return;
}
}
}
super.makeCall(origin, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
}
}
Aggregations