use of org.objectweb.asm.MethodVisitor 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) {
ClassNode dynamicCallReturnType = origin.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION);
if (dynamicCallReturnType != 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 (tryImplicitReceiver(origin, message, arguments, adapter, safe, spreadSafe, implicitThis)) {
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 = new ConstructorCallExpression(StaticCompilationVisitor.ARRAYLIST_CLASSNODE, ArgumentListExpression.EMPTY_ARGUMENTS);
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 = new VariableExpression(iterator);
MethodCallExpression origMCE = (MethodCallExpression) origin;
MethodCallExpression newMCE = new MethodCallExpression(iteratorAsVar, origMCE.getMethodAsString(), origMCE.getArguments());
newMCE.setImplicitThis(false);
newMCE.setMethodTarget(origMCE.getMethodTarget());
newMCE.setSafe(true);
MethodCallExpression add = new MethodCallExpression(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, new ExpressionStatement(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 = new MethodCallExpression(new VariableSlotLoader(slot.getType(), slot.getIndex(), controller.getOperandStack()), origMCE.getMethodAsString(), origMCE.getArguments());
MethodNode methodTarget = origMCE.getMethodTarget();
newMCE.setMethodTarget(methodTarget);
newMCE.setSafe(false);
newMCE.setImplicitThis(origMCE.isImplicitThis());
newMCE.setSourcePosition(origMCE);
newMCE.visit(controller.getAcg());
compileStack.removeVar(slot.getIndex());
ClassNode returnType = operandStack.getTopOperand();
if (ClassHelper.isPrimitiveType(returnType) && !ClassHelper.VOID_TYPE.equals(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 ((adapter == AsmClassGenerator.getGroovyObjectField || adapter == AsmClassGenerator.getField) && origin instanceof AttributeExpression) {
String pname = ((PropertyExpression) origin).getPropertyAsString();
CallSiteWriter callSiteWriter = controller.getCallSiteWriter();
if (pname != null && callSiteWriter instanceof StaticTypesCallSiteWriter) {
StaticTypesCallSiteWriter stcsw = (StaticTypesCallSiteWriter) callSiteWriter;
TypeChooser typeChooser = controller.getTypeChooser();
if (stcsw.makeGetField(receiver, typeChooser.resolveType(receiver, controller.getClassNode()), pname, safe, false, true)) {
return;
}
}
}
super.makeCall(origin, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
}
}
use of org.objectweb.asm.MethodVisitor 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());
}
}
}
}
use of org.objectweb.asm.MethodVisitor in project groovy by apache.
the class StaticTypesCallSiteWriter method makeGetPropertySite.
@Override
public void makeGetPropertySite(Expression receiver, final String methodName, final boolean safe, final boolean implicitThis) {
Object dynamic = receiver.getNodeMetaData(StaticCompilationMetadataKeys.RECEIVER_OF_DYNAMIC_PROPERTY);
if (dynamic != null) {
makeDynamicGetProperty(receiver, methodName, safe);
return;
}
TypeChooser typeChooser = controller.getTypeChooser();
ClassNode classNode = controller.getClassNode();
ClassNode receiverType = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
if (receiverType == null) {
receiverType = typeChooser.resolveType(receiver, classNode);
}
Object type = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (type == null && receiver instanceof VariableExpression) {
Variable variable = ((VariableExpression) receiver).getAccessedVariable();
if (variable instanceof Expression) {
type = ((Expression) variable).getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
}
}
if (type != null) {
// in case a "flow type" is found, it is preferred to use it instead of
// the declaration type
receiverType = (ClassNode) type;
}
boolean isClassReceiver = false;
if (isClassClassNodeWrappingConcreteType(receiverType)) {
isClassReceiver = true;
receiverType = receiverType.getGenericsTypes()[0].getType();
}
if (isPrimitiveType(receiverType)) {
// GROOVY-6590: wrap primitive types
receiverType = getWrapper(receiverType);
}
MethodVisitor mv = controller.getMethodVisitor();
if (receiverType.isArray() && methodName.equals("length")) {
receiver.visit(controller.getAcg());
ClassNode arrayGetReturnType = typeChooser.resolveType(receiver, classNode);
controller.getOperandStack().doGroovyCast(arrayGetReturnType);
mv.visitInsn(ARRAYLENGTH);
controller.getOperandStack().replace(int_TYPE);
return;
} else if ((receiverType.implementsInterface(COLLECTION_TYPE) || COLLECTION_TYPE.equals(receiverType)) && ("size".equals(methodName) || "length".equals(methodName))) {
MethodCallExpression expr = new MethodCallExpression(receiver, "size", ArgumentListExpression.EMPTY_ARGUMENTS);
expr.setMethodTarget(COLLECTION_SIZE_METHOD);
expr.setImplicitThis(implicitThis);
expr.setSafe(safe);
expr.visit(controller.getAcg());
return;
}
if (makeGetPropertyWithGetter(receiver, receiverType, methodName, safe, implicitThis))
return;
if (makeGetField(receiver, receiverType, methodName, safe, implicitThis, samePackages(receiverType.getPackageName(), classNode.getPackageName())))
return;
if (receiverType.isEnum()) {
mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(receiverType), methodName, BytecodeHelper.getTypeDescription(receiverType));
controller.getOperandStack().push(receiverType);
return;
}
if (receiver instanceof ClassExpression) {
if (makeGetField(receiver, receiver.getType(), methodName, safe, implicitThis, samePackages(receiver.getType().getPackageName(), classNode.getPackageName())))
return;
if (makeGetPropertyWithGetter(receiver, receiver.getType(), methodName, safe, implicitThis))
return;
if (makeGetPrivateFieldWithBridgeMethod(receiver, receiver.getType(), methodName, safe, implicitThis))
return;
}
if (isClassReceiver) {
// we are probably looking for a property of the class
if (makeGetPropertyWithGetter(receiver, CLASS_Type, methodName, safe, implicitThis))
return;
if (makeGetField(receiver, CLASS_Type, methodName, safe, false, true))
return;
}
if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, methodName, safe, implicitThis))
return;
// GROOVY-5580, it is still possible that we're calling a superinterface property
String getterName = "get" + MetaClassHelper.capitalize(methodName);
String altGetterName = "is" + MetaClassHelper.capitalize(methodName);
if (receiverType.isInterface()) {
Set<ClassNode> allInterfaces = receiverType.getAllInterfaces();
MethodNode getterMethod = null;
for (ClassNode anInterface : allInterfaces) {
getterMethod = anInterface.getGetterMethod(getterName);
if (getterMethod == null)
getterMethod = anInterface.getGetterMethod(altGetterName);
if (getterMethod != null)
break;
}
// GROOVY-5585
if (getterMethod == null) {
getterMethod = OBJECT_TYPE.getGetterMethod(getterName);
}
if (getterMethod != null) {
MethodCallExpression call = new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
call.setMethodTarget(getterMethod);
call.setImplicitThis(false);
call.setSourcePosition(receiver);
call.setSafe(safe);
call.visit(controller.getAcg());
return;
}
}
// GROOVY-5568, we would be facing a DGM call, but instead of foo.getText(), have foo.text
List<MethodNode> methods = findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), receiverType, getterName, ClassNode.EMPTY_ARRAY);
for (MethodNode m : findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), receiverType, altGetterName, ClassNode.EMPTY_ARRAY)) {
if (Boolean_TYPE.equals(getWrapper(m.getReturnType())))
methods.add(m);
}
if (!methods.isEmpty()) {
List<MethodNode> methodNodes = chooseBestMethod(receiverType, methods, ClassNode.EMPTY_ARRAY);
if (methodNodes.size() == 1) {
MethodNode getter = methodNodes.get(0);
MethodCallExpression call = new MethodCallExpression(receiver, getter.getName(), ArgumentListExpression.EMPTY_ARGUMENTS);
call.setMethodTarget(getter);
call.setImplicitThis(false);
call.setSafe(safe);
call.setSourcePosition(receiver);
call.visit(controller.getAcg());
return;
}
}
boolean isStaticProperty = receiver instanceof ClassExpression && (receiverType.isDerivedFrom(receiver.getType()) || receiverType.implementsInterface(receiver.getType()));
if (!isStaticProperty) {
if (receiverType.implementsInterface(MAP_TYPE) || MAP_TYPE.equals(receiverType)) {
// for maps, replace map.foo with map.get('foo')
writeMapDotProperty(receiver, methodName, mv, safe);
return;
}
if (receiverType.implementsInterface(LIST_TYPE) || LIST_TYPE.equals(receiverType)) {
writeListDotProperty(receiver, methodName, mv, safe);
return;
}
}
controller.getSourceUnit().addError(new SyntaxException("Access to " + (receiver instanceof ClassExpression ? receiver.getType() : receiverType).toString(false) + "#" + methodName + " is forbidden", receiver.getLineNumber(), receiver.getColumnNumber(), receiver.getLastLineNumber(), receiver.getLastColumnNumber()));
controller.getMethodVisitor().visitInsn(ACONST_NULL);
controller.getOperandStack().push(OBJECT_TYPE);
}
use of org.objectweb.asm.MethodVisitor in project groovy by apache.
the class StaticTypesCallSiteWriter method writeOperatorCall.
private void writeOperatorCall(Expression receiver, Expression arguments, String operator) {
prepareSiteAndReceiver(receiver, operator, false, controller.getCompileStack().isLHS());
controller.getOperandStack().doGroovyCast(Number_TYPE);
visitBoxedArgument(arguments);
controller.getOperandStack().doGroovyCast(Number_TYPE);
MethodVisitor mv = controller.getMethodVisitor();
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/typehandling/NumberMath", operator, "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;", false);
controller.getOperandStack().replace(Number_TYPE, 2);
}
use of org.objectweb.asm.MethodVisitor in project groovy by apache.
the class StaticTypesCallSiteWriter method writePowerCall.
private void writePowerCall(Expression receiver, Expression arguments, final ClassNode rType, ClassNode aType) {
OperandStack operandStack = controller.getOperandStack();
int m1 = operandStack.getStackLength();
//slow Path
prepareSiteAndReceiver(receiver, "power", false, controller.getCompileStack().isLHS());
operandStack.doGroovyCast(getWrapper(rType));
visitBoxedArgument(arguments);
operandStack.doGroovyCast(getWrapper(aType));
int m2 = operandStack.getStackLength();
MethodVisitor mv = controller.getMethodVisitor();
if (BigDecimal_TYPE.equals(rType) && Integer_TYPE.equals(getWrapper(aType))) {
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/math/BigDecimal;Ljava/lang/Integer;)Ljava/lang/Number;", false);
} else if (BigInteger_TYPE.equals(rType) && Integer_TYPE.equals(getWrapper(aType))) {
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/math/BigInteger;Ljava/lang/Integer;)Ljava/lang/Number;", false);
} else if (Long_TYPE.equals(getWrapper(rType)) && Integer_TYPE.equals(getWrapper(aType))) {
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Long;Ljava/lang/Integer;)Ljava/lang/Number;", false);
} else if (Integer_TYPE.equals(getWrapper(rType)) && Integer_TYPE.equals(getWrapper(aType))) {
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Number;", false);
} else {
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;", false);
}
controller.getOperandStack().replace(Number_TYPE, m2 - m1);
}
Aggregations