use of org.codehaus.groovy.classgen.asm.VariableSlotLoader 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.VariableSlotLoader in project groovy by apache.
the class StaticTypesBinaryExpressionMultiTypeDispatcher method assignToArray.
@Override
protected void assignToArray(final Expression enclosing, final Expression receiver, final Expression subscript, final Expression rhsValueLoader, final boolean safe) {
ClassNode receiverType = controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
if (receiverType.isArray() && !safe && binExpWriter[getOperandType(receiverType.getComponentType())].arraySet(true)) {
super.assignToArray(enclosing, receiver, subscript, rhsValueLoader, safe);
} else {
// GROOVY-6061
if (rhsValueLoader instanceof VariableSlotLoader && enclosing instanceof BinaryExpression) {
rhsValueLoader.putNodeMetaData(INFERRED_TYPE, controller.getTypeChooser().resolveType(enclosing, controller.getClassNode()));
}
// GROOVY-9771
receiver.visit(new StaticCompilationVisitor(controller.getSourceUnit(), controller.getClassNode()));
// replace assignment to a subscript operator with a method call
// e.g. x[5] = 10 -> methodCall(x, "putAt", [5, 10])
MethodCallExpression call = callX(receiver, "putAt", args(subscript, rhsValueLoader));
call.setSafe(safe);
call.setSourcePosition(enclosing);
OperandStack operandStack = controller.getOperandStack();
int height = operandStack.getStackLength();
call.visit(controller.getAcg());
operandStack.pop();
operandStack.remove(operandStack.getStackLength() - height);
// return value of assignment
rhsValueLoader.visit(controller.getAcg());
}
}
use of org.codehaus.groovy.classgen.asm.VariableSlotLoader in project groovy by apache.
the class StaticTypesCallSiteWriter method fallbackAttributeOrPropertySite.
@Override
public void fallbackAttributeOrPropertySite(final PropertyExpression expression, final Expression objectExpression, final String name, final MethodCallerMultiAdapter adapter) {
CompileStack compileStack = controller.getCompileStack();
OperandStack operandStack = controller.getOperandStack();
if (name != null && compileStack.isLHS()) {
boolean[] isClassReceiver = new boolean[1];
ClassNode receiverType = getPropertyOwnerType(objectExpression, isClassReceiver);
if (adapter == AsmClassGenerator.setField || adapter == AsmClassGenerator.setGroovyObjectField) {
if (setField(expression, objectExpression, receiverType, name))
return;
}
if (isThisExpression(objectExpression)) {
ClassNode classNode = controller.getClassNode();
FieldNode fieldNode = receiverType.getField(name);
if (fieldNode != null && fieldNode.isPrivate() && !receiverType.equals(classNode) && StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(receiverType, classNode)) {
Map<String, MethodNode> mutators = receiverType.redirect().getNodeMetaData(StaticCompilationMetadataKeys.PRIVATE_FIELDS_MUTATORS);
if (mutators != null) {
MethodNode methodNode = mutators.get(name);
if (methodNode != null) {
ClassNode rhsType = operandStack.getTopOperand();
int i = compileStack.defineTemporaryVariable("$rhs", rhsType, true);
VariableSlotLoader rhsValue = new VariableSlotLoader(rhsType, i, operandStack);
MethodCallExpression call = callX(objectExpression, methodNode.getName(), args(fieldNode.isStatic() ? nullX() : objectExpression, rhsValue));
call.setImplicitThis(expression.isImplicitThis());
call.setSpreadSafe(expression.isSpreadSafe());
call.setSafe(expression.isSafe());
call.setMethodTarget(methodNode);
call.visit(controller.getAcg());
// GROOVY-9892: assuming that the mutator method has a return value, make sure the operand
// stack is not polluted with the result of the method call
operandStack.pop();
compileStack.removeVar(i);
return;
}
}
}
}
if (isOrImplements(receiverType, MAP_TYPE) && !isClassReceiver[0]) {
MethodVisitor mv = controller.getMethodVisitor();
// store value in temporary variable
ClassNode rhsType = operandStack.getTopOperand();
int rhs = compileStack.defineTemporaryVariable("$rhs", rhsType, true);
// push receiver on stack
compileStack.pushLHS(false);
objectExpression.visit(controller.getAcg());
compileStack.popLHS();
// check if receiver null
Label skip = new Label();
if (expression.isSafe()) {
mv.visitInsn(DUP);
mv.visitJumpInsn(IFNULL, skip);
}
mv.visitLdcInsn(name);
BytecodeHelper.load(mv, rhsType, rhs);
if (isPrimitiveType(rhsType))
BytecodeHelper.doCastToWrappedType(mv, rhsType, getWrapper(rhsType));
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", true);
if (expression.isSafe()) {
mv.visitLabel(skip);
}
// no return value
operandStack.pop();
compileStack.removeVar(rhs);
return;
}
}
super.fallbackAttributeOrPropertySite(expression, objectExpression, name, adapter);
}
Aggregations