use of org.objectweb.asm.MethodVisitor in project groovy-core by groovy.
the class StaticTypesBinaryExpressionMultiTypeDispatcher method makeSetProperty.
private boolean makeSetProperty(final Expression receiver, final Expression message, final Expression arguments, final boolean safe, final boolean spreadSafe, final boolean implicitThis, final boolean isAttribute) {
WriterController controller = getController();
TypeChooser typeChooser = controller.getTypeChooser();
ClassNode receiverType = typeChooser.resolveType(receiver, controller.getClassNode());
String property = message.getText();
boolean isThisExpression = receiver instanceof VariableExpression && ((VariableExpression) receiver).isThisExpression();
if (isAttribute || (isThisExpression && receiverType.getDeclaredField(property) != null)) {
ClassNode current = receiverType;
FieldNode fn = null;
while (fn == null && current != null) {
fn = current.getDeclaredField(property);
if (fn == null) {
current = current.getSuperClass();
}
}
if (fn != null && receiverType != current && !fn.isPublic()) {
// check that direct access is allowed
if (!fn.isProtected()) {
return false;
}
String pkg1 = receiverType.getPackageName();
String pkg2 = current.getPackageName();
if (pkg1 != pkg2 && !pkg1.equals(pkg2)) {
return false;
}
OperandStack operandStack = controller.getOperandStack();
MethodVisitor mv = controller.getMethodVisitor();
if (!fn.isStatic()) {
receiver.visit(controller.getAcg());
}
arguments.visit(controller.getAcg());
operandStack.doGroovyCast(fn.getOriginType());
mv.visitFieldInsn(fn.isStatic() ? PUTSTATIC : PUTFIELD, BytecodeHelper.getClassInternalName(fn.getOwner()), property, BytecodeHelper.getTypeDescription(fn.getOriginType()));
operandStack.remove(fn.isStatic() ? 1 : 2);
return true;
}
}
if (!isAttribute) {
String setter = "set" + MetaClassHelper.capitalize(property);
MethodNode setterMethod = receiverType.getSetterMethod(setter);
ClassNode declaringClass = setterMethod != null ? setterMethod.getDeclaringClass() : null;
if (isThisExpression && declaringClass != null && declaringClass.equals(controller.getClassNode())) {
// this.x = ... shouldn't use a setter if in the same class
setterMethod = null;
} else if (setterMethod == null) {
PropertyNode propertyNode = receiverType.getProperty(property);
if (propertyNode != null) {
int mods = propertyNode.getModifiers();
if (!Modifier.isFinal(mods)) {
setterMethod = new MethodNode(setter, ACC_PUBLIC, ClassHelper.VOID_TYPE, new Parameter[] { new Parameter(propertyNode.getOriginType(), "value") }, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
setterMethod.setDeclaringClass(receiverType);
}
}
}
if (setterMethod != null) {
Expression call = StaticPropertyAccessHelper.transformToSetterCall(receiver, setterMethod, arguments, implicitThis, safe, spreadSafe, // to be replaced with a proper test whether a return value should be used or not
true, message);
call.visit(controller.getAcg());
return true;
}
}
return false;
}
use of org.objectweb.asm.MethodVisitor in project groovy-core by groovy.
the class StaticTypesBinaryExpressionMultiTypeDispatcher method transformSpreadOnLHS.
private void transformSpreadOnLHS(BinaryExpression origin) {
PropertyExpression spreadExpression = (PropertyExpression) origin.getLeftExpression();
Expression value = origin.getRightExpression();
WriterController controller = getController();
MethodVisitor mv = controller.getMethodVisitor();
CompileStack compileStack = controller.getCompileStack();
TypeChooser typeChooser = controller.getTypeChooser();
OperandStack operandStack = controller.getOperandStack();
ClassNode classNode = controller.getClassNode();
int counter = labelCounter.incrementAndGet();
Expression receiver = spreadExpression.getObjectExpression();
// create an empty arraylist
VariableExpression result = new VariableExpression(this.getClass().getSimpleName() + "$spreadresult" + counter, ARRAYLIST_CLASSNODE);
ConstructorCallExpression cce = new ConstructorCallExpression(ARRAYLIST_CLASSNODE, ArgumentListExpression.EMPTY_ARGUMENTS);
cce.setNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, ARRAYLIST_CONSTRUCTOR);
DeclarationExpression declr = new DeclarationExpression(result, Token.newSymbol("=", spreadExpression.getLineNumber(), spreadExpression.getColumnNumber()), cce);
declr.visit(controller.getAcg());
// if (receiver != null)
receiver.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(receiver, classNode));
Parameter iterator = new Parameter(componentType, "for$it$" + counter);
VariableExpression iteratorAsVar = new VariableExpression(iterator);
PropertyExpression pexp = spreadExpression instanceof AttributeExpression ? new AttributeExpression(iteratorAsVar, spreadExpression.getProperty(), true) : new PropertyExpression(iteratorAsVar, spreadExpression.getProperty(), true);
pexp.setImplicitThis(spreadExpression.isImplicitThis());
pexp.setSourcePosition(spreadExpression);
BinaryExpression assignment = new BinaryExpression(pexp, origin.getOperation(), value);
MethodCallExpression add = new MethodCallExpression(result, "add", assignment);
add.setMethodTarget(ARRAYLIST_ADD_METHOD);
// for (e in receiver) { result.add(e?.method(arguments) }
ForStatement stmt = new ForStatement(iterator, receiver, new ExpressionStatement(add));
stmt.visit(controller.getAcg());
// else { empty list }
mv.visitLabel(ifnull);
// end of if/else
// return result list
result.visit(controller.getAcg());
}
use of org.objectweb.asm.MethodVisitor in project groovy-core by groovy.
the class StaticTypesBinaryExpressionMultiTypeDispatcher method writePostOrPrefixMethod.
@Override
protected void writePostOrPrefixMethod(int op, String method, Expression expression, Expression orig) {
MethodNode mn = orig.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
WriterController controller = getController();
OperandStack operandStack = controller.getOperandStack();
if (mn != null) {
operandStack.pop();
MethodCallExpression call = new MethodCallExpression(expression, method, ArgumentListExpression.EMPTY_ARGUMENTS);
call.setMethodTarget(mn);
call.visit(controller.getAcg());
return;
}
ClassNode top = operandStack.getTopOperand();
if (ClassHelper.isPrimitiveType(top) && (ClassHelper.isNumberType(top) || char_TYPE.equals(top))) {
MethodVisitor mv = controller.getMethodVisitor();
if (WideningCategories.isIntCategory(top) || char_TYPE.equals(top)) {
mv.visitInsn(ICONST_1);
} else if (long_TYPE.equals(top)) {
mv.visitInsn(LCONST_1);
} else if (float_TYPE.equals(top)) {
mv.visitInsn(FCONST_1);
} else if (double_TYPE.equals(top)) {
mv.visitInsn(DCONST_1);
}
if ("next".equals(method)) {
if (WideningCategories.isIntCategory(top) || char_TYPE.equals(top)) {
mv.visitInsn(IADD);
} else if (long_TYPE.equals(top)) {
mv.visitInsn(LADD);
} else if (float_TYPE.equals(top)) {
mv.visitInsn(FADD);
} else if (double_TYPE.equals(top)) {
mv.visitInsn(DADD);
}
} else {
if (WideningCategories.isIntCategory(top) || char_TYPE.equals(top)) {
mv.visitInsn(ISUB);
} else if (long_TYPE.equals(top)) {
mv.visitInsn(LSUB);
} else if (float_TYPE.equals(top)) {
mv.visitInsn(FSUB);
} else if (double_TYPE.equals(top)) {
mv.visitInsn(DSUB);
}
}
return;
}
super.writePostOrPrefixMethod(op, method, expression, orig);
}
use of org.objectweb.asm.MethodVisitor in project groovy-core by groovy.
the class StatementWriter method writeTryCatchFinally.
public void writeTryCatchFinally(TryCatchStatement statement) {
controller.getAcg().onLineNumber(statement, "visitTryCatchFinally");
writeStatementLabel(statement);
MethodVisitor mv = controller.getMethodVisitor();
CompileStack compileStack = controller.getCompileStack();
OperandStack operandStack = controller.getOperandStack();
Statement tryStatement = statement.getTryStatement();
final Statement finallyStatement = statement.getFinallyStatement();
// start try block, label needed for exception table
Label tryStart = new Label();
mv.visitLabel(tryStart);
BlockRecorder tryBlock = makeBlockRecorder(finallyStatement);
tryBlock.startRange(tryStart);
tryStatement.visit(controller.getAcg());
// goto finally part
Label finallyStart = new Label();
mv.visitJumpInsn(GOTO, finallyStart);
Label tryEnd = new Label();
mv.visitLabel(tryEnd);
tryBlock.closeRange(tryEnd);
// pop for "makeBlockRecorder(finallyStatement)"
controller.getCompileStack().pop();
BlockRecorder catches = makeBlockRecorder(finallyStatement);
for (CatchStatement catchStatement : statement.getCatchStatements()) {
ClassNode exceptionType = catchStatement.getExceptionType();
String exceptionTypeInternalName = BytecodeHelper.getClassInternalName(exceptionType);
// start catch block, label needed for exception table
Label catchStart = new Label();
mv.visitLabel(catchStart);
catches.startRange(catchStart);
// create exception variable and store the exception
Parameter exceptionVariable = catchStatement.getVariable();
compileStack.pushState();
compileStack.defineVariable(exceptionVariable, true);
// handle catch body
catchStatement.visit(controller.getAcg());
// place holder to avoid problems with empty catch blocks
mv.visitInsn(NOP);
// pop for the variable
controller.getCompileStack().pop();
// end of catch
Label catchEnd = new Label();
mv.visitLabel(catchEnd);
catches.closeRange(catchEnd);
// goto finally start
mv.visitJumpInsn(GOTO, finallyStart);
compileStack.writeExceptionTable(tryBlock, catchStart, exceptionTypeInternalName);
}
// Label used to handle exceptions in catches and regularly
// visited finals.
Label catchAny = new Label();
// add "catch any" block to exception table for try part we do this
// after the exception blocks, because else this one would supersede
// any of those otherwise
compileStack.writeExceptionTable(tryBlock, catchAny, null);
// same for the catch parts
compileStack.writeExceptionTable(catches, catchAny, null);
// pop for "makeBlockRecorder(catches)"
compileStack.pop();
// start finally
mv.visitLabel(finallyStart);
finallyStatement.visit(controller.getAcg());
//**
mv.visitInsn(NOP);
// goto after all-catching block
Label skipCatchAll = new Label();
mv.visitJumpInsn(GOTO, skipCatchAll);
// start a block catching any Exception
mv.visitLabel(catchAny);
//store exception
//TODO: maybe define a Throwable and use it here instead of Object
operandStack.push(ClassHelper.OBJECT_TYPE);
int anyExceptionIndex = compileStack.defineTemporaryVariable("exception", true);
finallyStatement.visit(controller.getAcg());
// load the exception and rethrow it
mv.visitVarInsn(ALOAD, anyExceptionIndex);
mv.visitInsn(ATHROW);
mv.visitLabel(skipCatchAll);
}
use of org.objectweb.asm.MethodVisitor in project groovy-core by groovy.
the class StatementWriter method writeForLoopWithClosureList.
protected void writeForLoopWithClosureList(ForStatement loop) {
controller.getAcg().onLineNumber(loop, "visitForLoop");
writeStatementLabel(loop);
MethodVisitor mv = controller.getMethodVisitor();
controller.getCompileStack().pushLoop(loop.getVariableScope(), loop.getStatementLabels());
ClosureListExpression clExpr = (ClosureListExpression) loop.getCollectionExpression();
controller.getCompileStack().pushVariableScope(clExpr.getVariableScope());
List expressions = clExpr.getExpressions();
int size = expressions.size();
// middle element is condition, lower half is init, higher half is increment
int condIndex = (size - 1) / 2;
// visit init
for (int i = 0; i < condIndex; i++) {
visitExpressionOrStatement(expressions.get(i));
}
Label continueLabel = controller.getCompileStack().getContinueLabel();
Label breakLabel = controller.getCompileStack().getBreakLabel();
Label cond = new Label();
mv.visitLabel(cond);
// visit condition leave boolean on stack
{
Expression condExpr = (Expression) expressions.get(condIndex);
int mark = controller.getOperandStack().getStackLength();
condExpr.visit(controller.getAcg());
controller.getOperandStack().castToBool(mark, true);
}
// jump if we don't want to continue
// note: ifeq tests for ==0, a boolean is 0 if it is false
controller.getOperandStack().jump(IFEQ, breakLabel);
// Generate the loop body
loop.getLoopBlock().visit(controller.getAcg());
// visit increment
mv.visitLabel(continueLabel);
for (int i = condIndex + 1; i < size; i++) {
visitExpressionOrStatement(expressions.get(i));
}
// jump to test the condition again
mv.visitJumpInsn(GOTO, cond);
// loop end
mv.visitLabel(breakLabel);
controller.getCompileStack().pop();
controller.getCompileStack().pop();
}
Aggregations