/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.codehaus.groovy.classgen.asm; import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.runtime.BytecodeInterface8; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import static org.codehaus.groovy.syntax.Types.*; import static org.objectweb.asm.Opcodes.*; public class BinaryIntExpressionHelper extends BinaryExpressionWriter { private static final MethodCaller intArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "intArrayGet"); private static final MethodCaller intArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "intArraySet"); private static final int[] stdCompareCodes = { IF_ICMPEQ, // COMPARE_NOT_EQUAL 120 IF_ICMPNE, // COMPARE_IDENTICAL 121 IF_ICMPEQ, // COMPARE_NOT_IDENTICAL 122 IF_ICMPNE, // COMPARE_EQUAL 123 IF_ICMPGE, // COMPARE_LESS_THAN 124 IF_ICMPGT, // COMPARE_LESS_THAN_EQUAL 125 IF_ICMPLE, // COMPARE_GREATER_THAN 126 IF_ICMPLT, // COMPARE_GREATER_THAN_EQUAL 127 }; private static final int[] stdOperations = { IADD, // PLUS 200 ISUB, // MINUS 201 IMUL, // MULTIPLY 202 IDIV, // DIV 203 IDIV, // INTDIV 204 IREM, // MOD 203 }; private static final int[] bitOp = { IOR, // BITWISE_OR / PIPE 340 IAND, // BITWISE_AND 341 IXOR, // BIWISE_XOR 342 }; /* unhandled types from from org.codehaus.groovy.syntax.Types public static final int LOGICAL_OR = 162; // || public static final int LOGICAL_AND = 164; // && public static final int DIVIDE = 203; // / public static final int STAR_STAR = 206; // ** public static final int POWER = STAR_STAR; // public static final int PLUS_EQUAL = 210; // += public static final int MINUS_EQUAL = 211; // -= public static final int MULTIPLY_EQUAL = 212; // *= public static final int DIVIDE_EQUAL = 213; // /= public static final int INTDIV_EQUAL = 214; // \= public static final int MOD_EQUAL = 215; // %= public static final int POWER_EQUAL = 216; // **= public static final int PLUS_PLUS = 250; // ++ public static final int PREFIX_PLUS_PLUS = 251; // ++ public static final int POSTFIX_PLUS_PLUS = 252; // ++ public static final int PREFIX_PLUS = 253; // + public static final int MINUS_MINUS = 260; // -- public static final int PREFIX_MINUS_MINUS = 261; // -- public static final int POSTFIX_MINUS_MINUS = 262; // -- public static final int PREFIX_MINUS = 263; // - (negation) */ private static final int[] shiftOp = { ISHL, // LEFT_SHIFT 280 ISHR, // RIGHT_SHIFT 281 IUSHR // RIGHT_SHIFT_UNSIGNED 282 }; /* public static final int LEFT_SHIFT_EQUAL = 285; // <<= public static final int RIGHT_SHIFT_EQUAL = 286; // >>= public static final int RIGHT_SHIFT_UNSIGNED_EQUAL = 287; // >>>= public static final int BITWISE_OR_EQUAL = 350; // |= public static final int BITWISE_AND_EQUAL = 351; // &= public static final int BITWISE_XOR_EQUAL = 352; // ^= public static final int BITWISE_NEGATION = REGEX_PATTERN; // ~ */ public BinaryIntExpressionHelper(WriterController wc) { this(wc, intArraySet, intArrayGet); } /** * @since 2.5.0 */ public BinaryIntExpressionHelper(WriterController wc, MethodCaller arraySet, MethodCaller arrayGet) { super(wc, arraySet, arrayGet); } /** * writes a std compare. This involves the tokens IF_ICMPEQ, IF_ICMPNE, * IF_ICMPEQ, IF_ICMPNE, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE and IF_ICMPLT * @param type the token type * @return true if a successful std compare write */ protected boolean writeStdCompare(int type, boolean simulate) { type = type-COMPARE_NOT_EQUAL; // look if really compare if (type<0||type>7) return false; if (!simulate) { MethodVisitor mv = getController().getMethodVisitor(); OperandStack operandStack = getController().getOperandStack(); // operands are on the stack already int bytecode = stdCompareCodes[type]; Label l1 = new Label(); mv.visitJumpInsn(bytecode,l1); mv.visitInsn(ICONST_1); Label l2 = new Label(); mv.visitJumpInsn(GOTO, l2); mv.visitLabel(l1); mv.visitInsn(ICONST_0); mv.visitLabel(l2); operandStack.replace(ClassHelper.boolean_TYPE, 2); } return true; } /** * writes the spaceship operator, type should be COMPARE_TO * @param type the token type * @return true if a successful spaceship operator write */ protected boolean writeSpaceship(int type, boolean simulate) { if (type != COMPARE_TO) return false; /* we will actually do (x < y) ? -1 : ((x == y) ? 0 : 1) which is the essence of what the call with Integers would do this compiles to something along <x> <y> IF_ICMPGE L1 ICONST_M1 GOTO L2 L1 <x> <y> IF_ICMPNE L3 ICONST_0 GOTO L2 L3 ICONST_1 L2 since the operators are already on the stack and we don't want to load them again, we will instead duplicate them. This will require some pop actions in the branches! DUP2 (operands: IIII) IF_ICMPGE L1 (operands: II) ICONST_M1 (operands: III) GOTO L2 L1 ----- (operands: II) IF_ICMPNE L3 (operands: -) ICONST_0 (operands: I) GOTO L2 L3 - jump from L1 branch to here (operands: -) ICONST_1 (operands: I) L2 - if jump from GOTO L2 we have III, but need only I - if from L3 branch we get only I this means we have to pop of II before loading -1 */ if (!simulate) { MethodVisitor mv = getController().getMethodVisitor(); // duplicate int arguments mv.visitInsn(DUP2); Label l1 = new Label(); mv.visitJumpInsn(IF_ICMPGE,l1); // no jump, so -1, need to pop off surplus II mv.visitInsn(POP2); mv.visitInsn(ICONST_M1); Label l2 = new Label(); mv.visitJumpInsn(GOTO, l2); mv.visitLabel(l1); Label l3 = new Label(); mv.visitJumpInsn(IF_ICMPNE,l3); mv.visitInsn(ICONST_0); mv.visitJumpInsn(GOTO,l2); mv.visitLabel(l3); mv.visitInsn(ICONST_1); getController().getOperandStack().replace(ClassHelper.int_TYPE, 2); } return true; } protected void doubleTwoOperands(MethodVisitor mv) { mv.visitInsn(DUP2); } protected int getBitwiseOperationBytecode(int type) { return bitOp[type]; } protected int getCompareCode() { return -1; } protected ClassNode getNormalOpResultType() { return ClassHelper.int_TYPE; } protected int getShiftOperationBytecode(int type) { return shiftOp[type]; } protected int getStandardOperationBytecode(int type) { return stdOperations[type]; } protected void removeTwoOperands(MethodVisitor mv) { mv.visitInsn(POP2); } protected void writeMinusMinus(MethodVisitor mv) { mv.visitInsn(ICONST_1); mv.visitInsn(ISUB); } protected void writePlusPlus(MethodVisitor mv) { mv.visitInsn(ICONST_1); mv.visitInsn(IADD); } protected ClassNode getDevisionOpResultType() { return ClassHelper.int_TYPE; } @Override protected boolean supportsDivision() { return true; } }