@Override protected void assignToArray( Expression orig, Expression receiver, Expression index, Expression rhsValueLoader) { ClassNode current = getController().getClassNode(); ClassNode arrayType = getController().getTypeChooser().resolveType(receiver, current); ClassNode arrayComponentType = arrayType.getComponentType(); int operationType = getOperandType(arrayComponentType); BinaryExpressionWriter bew = binExpWriter[operationType]; AsmClassGenerator acg = getController().getAcg(); if (bew.arraySet(true) && arrayType.isArray()) { OperandStack operandStack = getController().getOperandStack(); // load the array receiver.visit(acg); operandStack.doGroovyCast(arrayType); // load index index.visit(acg); operandStack.doGroovyCast(int_TYPE); // load rhs rhsValueLoader.visit(acg); operandStack.doGroovyCast(arrayComponentType); // store value in array bew.arraySet(false); // load return value && correct operand stack stack operandStack.remove(3); rhsValueLoader.visit(acg); } else { super.assignToArray(orig, receiver, index, rhsValueLoader); } }
private void execMethodAndStoreForSubscriptOperator( int op, String method, Expression expression, VariableSlotLoader usesSubscript, Expression orig) { final OperandStack operandStack = controller.getOperandStack(); writePostOrPrefixMethod(op, method, expression, orig); // we need special code for arrays to store the result (like for a[1]++) if (usesSubscript != null) { CompileStack compileStack = controller.getCompileStack(); BinaryExpression be = (BinaryExpression) expression; ClassNode methodResultType = operandStack.getTopOperand(); final int resultIdx = compileStack.defineTemporaryVariable("postfix_" + method, methodResultType, true); BytecodeExpression methodResultLoader = new VariableSlotLoader(methodResultType, resultIdx, operandStack); // execute the assignment, this will leave the right side // (here the method call result) on the stack assignToArray(be, be.getLeftExpression(), usesSubscript, methodResultLoader); compileStack.removeVar(resultIdx); } // here we handle a.b++ and a++ else if (expression instanceof VariableExpression || expression instanceof FieldExpression || expression instanceof PropertyExpression) { operandStack.dup(); controller.getCompileStack().pushLHS(true); expression.visit(controller.getAcg()); controller.getCompileStack().popLHS(); } // other cases don't need storing, so nothing to be done for them }
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(); } // ensure we try to unbox null to cause a runtime NPE in case we assign // null to a primitive typed variable, even if it is used only in boxed // 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); } } } // single declaration else if (defineVariable) { rhsValueLoader.visit(acg); operandStack.remove(1); compileStack.popLHS(); return; } // normal assignment else { 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); }