use of org.codehaus.groovy.classgen.asm.TypeChooser in project groovy by apache.
the class StaticTypesCallSiteWriter method makeSingleArgumentCall.
@Override
public void makeSingleArgumentCall(final Expression receiver, final String message, final Expression arguments, final boolean safe) {
TypeChooser typeChooser = controller.getTypeChooser();
ClassNode classNode = controller.getClassNode();
ClassNode rType = typeChooser.resolveType(receiver, classNode);
ClassNode aType = typeChooser.resolveType(arguments, classNode);
if (trySubscript(receiver, message, arguments, rType, aType, safe)) {
return;
}
// now try with flow type instead of declaration type
rType = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (receiver instanceof VariableExpression && rType == null) {
// TODO: can STCV be made smarter to avoid this check?
ASTNode node = (ASTNode) ((VariableExpression) receiver).getAccessedVariable();
rType = node.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
}
if (rType != null && trySubscript(receiver, message, arguments, rType, aType, safe)) {
return;
}
// todo: more cases
throw new GroovyBugError("At line " + receiver.getLineNumber() + " column " + receiver.getColumnNumber() + "\n" + "On receiver: " + receiver.getText() + " with message: " + message + " and arguments: " + arguments.getText() + "\n" + "This method should not have been called. Please try to create a simple example reproducing\n" + "this error and file a bug report at https://issues.apache.org/jira/browse/GROOVY");
}
use of org.codehaus.groovy.classgen.asm.TypeChooser in project groovy by apache.
the class StaticInvocationWriter method loadArguments.
@Override
protected void loadArguments(final List<Expression> argumentList, final Parameter[] parameters) {
final int nArgs = argumentList.size(), nPrms = parameters.length;
if (nPrms == 0)
return;
ClassNode classNode = controller.getClassNode();
TypeChooser typeChooser = controller.getTypeChooser();
ClassNode lastArgType = nArgs == 0 ? null : typeChooser.resolveType(argumentList.get(nArgs - 1), classNode);
ClassNode lastPrmType = parameters[nPrms - 1].getOriginType();
// target is variadic and args are too many or one short or just enough with array compatibility
if (lastPrmType.isArray() && (nArgs > nPrms || nArgs == nPrms - 1 || (nArgs == nPrms && !lastArgType.isArray() && (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType, lastPrmType.getComponentType()) || isGStringType(lastArgType) && isStringType(lastPrmType.getComponentType()))))) {
OperandStack operandStack = controller.getOperandStack();
int stackLength = operandStack.getStackLength() + nArgs;
// first arguments/parameters as usual
for (int i = 0; i < nPrms - 1; i += 1) {
visitArgument(argumentList.get(i), parameters[i].getType());
}
// wrap remaining arguments in an array for last parameter
List<Expression> lastArgs = new ArrayList<>();
for (int i = nPrms - 1; i < nArgs; i += 1) {
lastArgs.add(argumentList.get(i));
}
ArrayExpression array = new ArrayExpression(lastPrmType.getComponentType(), lastArgs);
array.visit(controller.getAcg());
// adjust stack length
while (operandStack.getStackLength() < stackLength) {
operandStack.push(ClassHelper.OBJECT_TYPE);
}
if (nArgs == nPrms - 1) {
operandStack.remove(1);
}
} else if (nArgs == nPrms) {
for (int i = 0; i < nArgs; i += 1) {
visitArgument(argumentList.get(i), parameters[i].getType());
}
} else {
// call with default arguments
Expression[] arguments = new Expression[nPrms];
for (int i = 0, j = 0; i < nPrms; i += 1) {
Parameter p = parameters[i];
ClassNode pType = p.getType();
Expression a = (j < nArgs ? argumentList.get(j) : null);
ClassNode aType = (a == null ? null : typeChooser.resolveType(a, classNode));
// default argument
Expression expression = getInitialExpression(p);
if (expression != null && !isCompatibleArgumentType(aType, pType)) {
arguments[i] = expression;
} else if (a != null) {
arguments[i] = a;
j += 1;
} else {
controller.getSourceUnit().addFatalError("Binding failed" + " for arguments [" + argumentList.stream().map(arg -> typeChooser.resolveType(arg, classNode).toString(false)).collect(Collectors.joining(", ")) + "]" + " and parameters [" + Arrays.stream(parameters).map(prm -> prm.getType().toString(false)).collect(Collectors.joining(", ")) + "]", getCurrentCall());
}
}
for (int i = 0; i < nArgs; i += 1) {
visitArgument(arguments[i], parameters[i].getType());
}
}
}
use of org.codehaus.groovy.classgen.asm.TypeChooser 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);
}
}
use of org.codehaus.groovy.classgen.asm.TypeChooser in project groovy-core by groovy.
the class StaticTypesUnaryExpressionHelper method writeNotExpression.
@Override
public void writeNotExpression(final NotExpression expression) {
TypeChooser typeChooser = controller.getTypeChooser();
Expression subExpression = expression.getExpression();
ClassNode classNode = controller.getClassNode();
if (typeChooser.resolveType(subExpression, classNode) == boolean_TYPE) {
subExpression.visit(controller.getAcg());
controller.getOperandStack().doGroovyCast(boolean_TYPE);
BytecodeExpression bytecodeExpression = new BytecodeExpression() {
@Override
public void visit(final MethodVisitor mv) {
Label ne = new Label();
mv.visitJumpInsn(IFNE, ne);
mv.visitInsn(ICONST_1);
Label out = new Label();
mv.visitJumpInsn(GOTO, out);
mv.visitLabel(ne);
mv.visitInsn(ICONST_0);
mv.visitLabel(out);
}
};
bytecodeExpression.visit(controller.getAcg());
controller.getOperandStack().remove(1);
return;
}
super.writeNotExpression(expression);
}
use of org.codehaus.groovy.classgen.asm.TypeChooser in project groovy by apache.
the class StaticTypesUnaryExpressionHelper method writeNotExpression.
@Override
public void writeNotExpression(final NotExpression expression) {
Expression subExpression = expression.getExpression();
TypeChooser typeChooser = controller.getTypeChooser();
if (isPrimitiveBoolean(typeChooser.resolveType(subExpression, controller.getClassNode()))) {
subExpression.visit(controller.getAcg());
controller.getOperandStack().doGroovyCast(boolean_TYPE);
bytecodeX(mv -> {
Label ne = new Label();
mv.visitJumpInsn(IFNE, ne);
mv.visitInsn(ICONST_1);
Label out = new Label();
mv.visitJumpInsn(GOTO, out);
mv.visitLabel(ne);
mv.visitInsn(ICONST_0);
mv.visitLabel(out);
}).visit(controller.getAcg());
controller.getOperandStack().remove(1);
} else {
super.writeNotExpression(expression);
}
}
Aggregations