use of org.codehaus.groovy.classgen.AsmClassGenerator in project groovy by apache.
the class BinaryExpressionHelper method evaluateEqual.
public void evaluateEqual(BinaryExpression expression, boolean defineVariable) {
AsmClassGenerator acg = controller.getAcg();
CompileStack compileStack = controller.getCompileStack();
OperandStack operandStack = controller.getOperandStack();
Expression rightExpression = expression.getRightExpression();
Expression leftExpression = expression.getLeftExpression();
ClassNode lhsType = controller.getTypeChooser().resolveType(leftExpression, controller.getClassNode());
if (defineVariable && rightExpression instanceof EmptyExpression && !(leftExpression instanceof TupleExpression)) {
VariableExpression ve = (VariableExpression) leftExpression;
BytecodeVariable var = compileStack.defineVariable(ve, controller.getTypeChooser().resolveType(ve, controller.getClassNode()), false);
operandStack.loadOrStoreVariable(var, false);
return;
}
// let's evaluate the RHS and store the result
ClassNode rhsType;
if (rightExpression instanceof ListExpression && lhsType.isArray()) {
ListExpression list = (ListExpression) rightExpression;
ArrayExpression array = new ArrayExpression(lhsType.getComponentType(), list.getExpressions());
array.setSourcePosition(list);
array.visit(acg);
} else if (rightExpression instanceof EmptyExpression) {
rhsType = leftExpression.getType();
loadInitValue(rhsType);
} else {
rightExpression.visit(acg);
}
rhsType = operandStack.getTopOperand();
boolean directAssignment = defineVariable && !(leftExpression instanceof TupleExpression);
int rhsValueId;
if (directAssignment) {
VariableExpression var = (VariableExpression) leftExpression;
if (var.isClosureSharedVariable() && ClassHelper.isPrimitiveType(rhsType)) {
// GROOVY-5570: if a closure shared variable is a primitive type, it must be boxed
rhsType = ClassHelper.getWrapper(rhsType);
operandStack.box();
}
// form as it is closure shared
if (var.isClosureSharedVariable() && ClassHelper.isPrimitiveType(var.getOriginType()) && isNull(rightExpression)) {
operandStack.doGroovyCast(var.getOriginType());
// these two are never reached in bytecode and only there
// to avoid verifyerrors and compiler infrastructure hazzle
operandStack.box();
operandStack.doGroovyCast(lhsType);
}
// normal type transformation
if (!ClassHelper.isPrimitiveType(lhsType) && isNull(rightExpression)) {
operandStack.replace(lhsType);
} else {
operandStack.doGroovyCast(lhsType);
}
rhsType = lhsType;
rhsValueId = compileStack.defineVariable(var, lhsType, true).getIndex();
} else {
rhsValueId = compileStack.defineTemporaryVariable("$rhs", rhsType, true);
}
//TODO: if rhs is VariableSlotLoader already, then skip crating a new one
BytecodeExpression rhsValueLoader = new VariableSlotLoader(rhsType, rhsValueId, operandStack);
// assignment for subscript
if (leftExpression instanceof BinaryExpression) {
BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
assignToArray(expression, leftBinExpr.getLeftExpression(), leftBinExpr.getRightExpression(), rhsValueLoader);
}
compileStack.removeVar(rhsValueId);
return;
}
compileStack.pushLHS(true);
// multiple declaration
if (leftExpression instanceof TupleExpression) {
TupleExpression tuple = (TupleExpression) leftExpression;
int i = 0;
for (Expression e : tuple.getExpressions()) {
VariableExpression var = (VariableExpression) e;
MethodCallExpression call = new MethodCallExpression(rhsValueLoader, "getAt", new ArgumentListExpression(new ConstantExpression(i)));
call.visit(acg);
i++;
if (defineVariable) {
operandStack.doGroovyCast(var);
compileStack.defineVariable(var, true);
operandStack.remove(1);
} else {
acg.visitVariableExpression(var);
}
}
} else // single declaration
if (defineVariable) {
rhsValueLoader.visit(acg);
operandStack.remove(1);
compileStack.popLHS();
return;
} else // normal assignment
{
int mark = operandStack.getStackLength();
// to leave a copy of the rightExpression value on the stack after the assignment.
rhsValueLoader.visit(acg);
TypeChooser typeChooser = controller.getTypeChooser();
ClassNode targetType = typeChooser.resolveType(leftExpression, controller.getClassNode());
operandStack.doGroovyCast(targetType);
leftExpression.visit(acg);
operandStack.remove(operandStack.getStackLength() - mark);
}
compileStack.popLHS();
// return value of assignment
rhsValueLoader.visit(acg);
compileStack.removeVar(rhsValueId);
}
use of org.codehaus.groovy.classgen.AsmClassGenerator in project groovy by apache.
the class BinaryExpressionHelper method evaluateArrayAssignmentWithOperator.
protected void evaluateArrayAssignmentWithOperator(String method, BinaryExpression expression, BinaryExpression leftBinExpr) {
CompileStack compileStack = getController().getCompileStack();
AsmClassGenerator acg = getController().getAcg();
OperandStack os = getController().getOperandStack();
// e.g. x[a] += b
// to avoid loading x and a twice we transform the expression to use
// ExpressionAsVariableSlot
// -> subscript=a, receiver=x, receiver[subscript]+b, =, receiver[subscript]
// -> subscript=a, receiver=x, receiver#getAt(subscript)#plus(b), =, receiver#putAt(subscript)
// -> subscript=a, receiver=x, receiver#putAt(subscript, receiver#getAt(subscript)#plus(b))
// the result of x[a] += b is x[a]+b, thus:
// -> subscript=a, receiver=x, receiver#putAt(subscript, ret=receiver#getAt(subscript)#plus(b)), ret
ExpressionAsVariableSlot subscript = new ExpressionAsVariableSlot(controller, leftBinExpr.getRightExpression(), "subscript");
ExpressionAsVariableSlot receiver = new ExpressionAsVariableSlot(controller, leftBinExpr.getLeftExpression(), "receiver");
MethodCallExpression getAt = new MethodCallExpression(receiver, "getAt", new ArgumentListExpression(subscript));
MethodCallExpression operation = new MethodCallExpression(getAt, method, expression.getRightExpression());
ExpressionAsVariableSlot ret = new ExpressionAsVariableSlot(controller, operation, "ret");
MethodCallExpression putAt = new MethodCallExpression(receiver, "putAt", new ArgumentListExpression(subscript, ret));
putAt.visit(acg);
os.pop();
os.load(ret.getType(), ret.getIndex());
compileStack.removeVar(ret.getIndex());
compileStack.removeVar(subscript.getIndex());
compileStack.removeVar(receiver.getIndex());
}
use of org.codehaus.groovy.classgen.AsmClassGenerator in project groovy by apache.
the class BinaryExpressionMultiTypeDispatcher method doAssignmentToArray.
private boolean doAssignmentToArray(BinaryExpression binExp) {
if (!isAssignmentToArray(binExp))
return false;
// we need to handle only assignment to arrays combined with an operation
// special here. e.g x[a] += b
int operation = removeAssignment(binExp.getOperation().getType());
ClassNode current = getController().getClassNode();
Expression leftExp = binExp.getLeftExpression();
ClassNode leftType = getController().getTypeChooser().resolveType(leftExp, current);
Expression rightExp = binExp.getRightExpression();
ClassNode rightType = getController().getTypeChooser().resolveType(rightExp, current);
int operationType = getOperandType(leftType);
BinaryExpressionWriter bew = binExpWriter[operationType];
boolean simulationSuccess = bew.arrayGet(LEFT_SQUARE_BRACKET, true);
simulationSuccess = simulationSuccess && bew.write(operation, true);
simulationSuccess = simulationSuccess && bew.arraySet(true);
if (!simulationSuccess)
return false;
AsmClassGenerator acg = getController().getAcg();
OperandStack operandStack = getController().getOperandStack();
CompileStack compileStack = getController().getCompileStack();
// for x[a] += b we have the structure:
// x = left(left(binExp))), b = right(binExp), a = right(left(binExp)))
// for array set we need these values on stack: array, index, right
// for array get we need these values on stack: array, index
// to eval the expression we need x[a] = x[a]+b
// -> arraySet(x,a, x[a]+b)
// -> arraySet(x,a, arrayGet(x,a,b))
// --> x,a, x,a, b as operands
// --> load x, load a, DUP2, call arrayGet, load b, call operation,call arraySet
// since we cannot DUP2 here easily we will save the subscript and DUP x
// --> sub=a, load x, DUP, load sub, call arrayGet, load b, call operation, load sub, call arraySet
BinaryExpression arrayWithSubscript = (BinaryExpression) leftExp;
Expression subscript = arrayWithSubscript.getRightExpression();
// load array index: sub=a [load x, DUP, load sub, call arrayGet, load b, call operation, load sub, call arraySet]
subscript.visit(acg);
operandStack.doGroovyCast(int_TYPE);
int subscriptValueId = compileStack.defineTemporaryVariable("$sub", ClassHelper.int_TYPE, true);
// load array: load x and DUP [load sub, call arrayGet, load b, call operation, load sub, call arraySet]
arrayWithSubscript.getLeftExpression().visit(acg);
operandStack.doGroovyCast(leftType.makeArray());
operandStack.dup();
// array get: load sub, call arrayGet [load b, call operation, load sub, call arraySet]
operandStack.load(ClassHelper.int_TYPE, subscriptValueId);
bew.arrayGet(LEFT_SQUARE_BRACKET, false);
operandStack.replace(leftType, 2);
// complete rhs: load b, call operation [load sub, call arraySet]
binExp.getRightExpression().visit(acg);
if (!(bew instanceof BinaryObjectExpressionHelper)) {
// in primopts we convert to the left type for supported binary operations
operandStack.doGroovyCast(leftType);
}
bew.write(operation, false);
// let us save that value for the return
operandStack.dup();
int resultValueId = compileStack.defineTemporaryVariable("$result", rightType, true);
// array set: load sub, call arraySet []
operandStack.load(ClassHelper.int_TYPE, subscriptValueId);
operandStack.swap();
bew.arraySet(false);
// 3 operands, the array, the index and the value!
operandStack.remove(3);
// load return value
operandStack.load(rightType, resultValueId);
// cleanup
compileStack.removeVar(resultValueId);
compileStack.removeVar(subscriptValueId);
return true;
}
use of org.codehaus.groovy.classgen.AsmClassGenerator in project groovy by apache.
the class ClosureWriter method addGeneratedClosureConstructorCall.
public boolean addGeneratedClosureConstructorCall(ConstructorCallExpression call) {
ClassNode classNode = controller.getClassNode();
if (!classNode.declaresInterface(ClassHelper.GENERATED_CLOSURE_Type))
return false;
AsmClassGenerator acg = controller.getAcg();
OperandStack operandStack = controller.getOperandStack();
MethodVisitor mv = controller.getMethodVisitor();
mv.visitVarInsn(ALOAD, 0);
ClassNode callNode = classNode.getSuperClass();
TupleExpression arguments = (TupleExpression) call.getArguments();
if (arguments.getExpressions().size() != 2)
throw new GroovyBugError("expected 2 arguments for closure constructor super call, but got" + arguments.getExpressions().size());
arguments.getExpression(0).visit(acg);
operandStack.box();
arguments.getExpression(1).visit(acg);
operandStack.box();
//TODO: replace with normal String, p not needed
Parameter p = new Parameter(ClassHelper.OBJECT_TYPE, "_p");
String descriptor = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, new Parameter[] { p, p });
mv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(callNode), "<init>", descriptor, false);
operandStack.remove(2);
return true;
}
use of org.codehaus.groovy.classgen.AsmClassGenerator in project groovy by apache.
the class StaticInvocationWriter method loadArguments.
protected void loadArguments(List<Expression> argumentList, Parameter[] para) {
if (para.length == 0)
return;
ClassNode lastParaType = para[para.length - 1].getOriginType();
AsmClassGenerator acg = controller.getAcg();
TypeChooser typeChooser = controller.getTypeChooser();
OperandStack operandStack = controller.getOperandStack();
ClassNode lastArgType = !argumentList.isEmpty() ? typeChooser.resolveType(argumentList.get(argumentList.size() - 1), controller.getClassNode()) : null;
if (lastParaType.isArray() && ((argumentList.size() > para.length) || ((argumentList.size() == (para.length - 1)) && !lastParaType.equals(lastArgType)) || ((argumentList.size() == para.length && lastArgType != null && !lastArgType.isArray()) && (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType, lastParaType.getComponentType()))) || ClassHelper.GSTRING_TYPE.equals(lastArgType) && ClassHelper.STRING_TYPE.equals(lastParaType.getComponentType()))) {
int stackLen = operandStack.getStackLength() + argumentList.size();
MethodVisitor mv = controller.getMethodVisitor();
//mv = new org.objectweb.asm.util.TraceMethodVisitor(mv);
controller.setMethodVisitor(mv);
// first parameters as usual
for (int i = 0; i < para.length - 1; i++) {
Expression expression = argumentList.get(i);
expression.visit(acg);
if (!isNullConstant(expression)) {
operandStack.doGroovyCast(para[i].getType());
}
}
// last parameters wrapped in an array
List<Expression> lastParams = new LinkedList<Expression>();
for (int i = para.length - 1; i < argumentList.size(); i++) {
lastParams.add(argumentList.get(i));
}
ArrayExpression array = new ArrayExpression(lastParaType.getComponentType(), lastParams);
array.visit(acg);
// adjust stack length
while (operandStack.getStackLength() < stackLen) {
operandStack.push(ClassHelper.OBJECT_TYPE);
}
if (argumentList.size() == para.length - 1) {
operandStack.remove(1);
}
} else if (argumentList.size() == para.length) {
for (int i = 0; i < argumentList.size(); i++) {
Expression expression = argumentList.get(i);
expression.visit(acg);
if (!isNullConstant(expression)) {
operandStack.doGroovyCast(para[i].getType());
}
}
} else {
// method call with default arguments
ClassNode classNode = controller.getClassNode();
Expression[] arguments = new Expression[para.length];
for (int i = 0, j = 0; i < para.length; i++) {
Parameter curParam = para[i];
ClassNode curParamType = curParam.getType();
Expression curArg = j < argumentList.size() ? argumentList.get(j) : null;
Expression initialExpression = (Expression) curParam.getNodeMetaData(StaticTypesMarker.INITIAL_EXPRESSION);
if (initialExpression == null && curParam.hasInitialExpression())
initialExpression = curParam.getInitialExpression();
if (initialExpression == null && curParam.getNodeMetaData(Verifier.INITIAL_EXPRESSION) != null) {
initialExpression = (Expression) curParam.getNodeMetaData(Verifier.INITIAL_EXPRESSION);
}
ClassNode curArgType = curArg == null ? null : typeChooser.resolveType(curArg, classNode);
if (initialExpression != null && !compatibleArgumentType(curArgType, curParamType)) {
// use default expression
arguments[i] = initialExpression;
} else {
arguments[i] = curArg;
j++;
}
}
for (int i = 0; i < arguments.length; i++) {
Expression expression = arguments[i];
expression.visit(acg);
if (!isNullConstant(expression)) {
operandStack.doGroovyCast(para[i].getType());
}
}
}
}
Aggregations