/* * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.truffle.dsl.processor.model; import java.util.Arrays; import java.util.HashSet; import java.util.Objects; import java.util.Set; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import com.oracle.truffle.dsl.processor.ProcessorContext; import com.oracle.truffle.dsl.processor.expression.DSLExpression; import com.oracle.truffle.dsl.processor.expression.DSLExpression.AbstractDSLExpressionReducer; import com.oracle.truffle.dsl.processor.expression.DSLExpression.Binary; import com.oracle.truffle.dsl.processor.expression.DSLExpression.BooleanLiteral; import com.oracle.truffle.dsl.processor.expression.DSLExpression.Call; import com.oracle.truffle.dsl.processor.expression.DSLExpression.Negate; import com.oracle.truffle.dsl.processor.expression.DSLExpression.Variable; import com.oracle.truffle.dsl.processor.java.ElementUtils; public final class GuardExpression extends MessageContainer { private static final Set<String> IDENTITY_FOLD_OPERATORS = new HashSet<>(Arrays.asList("<=", ">=", "==")); private final SpecializationData source; private final DSLExpression expression; public GuardExpression(SpecializationData source, DSLExpression expression) { this.source = source; this.expression = expression; } @Override public Element getMessageElement() { return source.getMessageElement(); } @Override public AnnotationMirror getMessageAnnotation() { return source.getMessageAnnotation(); } @Override public AnnotationValue getMessageAnnotationValue() { return ElementUtils.getAnnotationValue(getMessageAnnotation(), "guards"); } public DSLExpression getExpression() { return expression; } public boolean isConstantTrueInSlowPath(ProcessorContext context) { DSLExpression reducedExpression = getExpression().reduce(new AbstractDSLExpressionReducer() { @Override public DSLExpression visitVariable(Variable binary) { // on the slow path we can assume all cache expressions inlined. for (CacheExpression cache : source.getCaches()) { if (ElementUtils.variableEquals(cache.getParameter().getVariableElement(), binary.getResolvedVariable())) { return cache.getExpression(); } } return super.visitVariable(binary); } @Override public DSLExpression visitCall(Call binary) { ExecutableElement method = binary.getResolvedMethod(); if (!method.getSimpleName().toString().equals("equals")) { return binary; } if (method.getModifiers().contains(Modifier.STATIC)) { return binary; } if (!ElementUtils.typeEquals(method.getReturnType(), context.getType(boolean.class))) { return binary; } if (method.getParameters().size() != 1) { return binary; } // signature: receiver.equals(receiver) can be folded to true DSLExpression receiver = binary.getReceiver(); DSLExpression firstArg = binary.getParameters().get(0); if (receiver instanceof Variable && firstArg instanceof Variable) { if (receiver.equals(firstArg)) { return new BooleanLiteral(true); } } return super.visitCall(binary); } @Override public DSLExpression visitBinary(Binary binary) { // signature: value == value can be folded to true if (IDENTITY_FOLD_OPERATORS.contains(binary.getOperator())) { if (binary.getLeft() instanceof Variable && binary.getRight() instanceof Variable) { Variable leftVar = ((Variable) binary.getLeft()); Variable rightVar = ((Variable) binary.getRight()); if (leftVar.equals(rightVar)) { // double and float cannot be folded as NaN is never identity equal if (!ElementUtils.typeEquals(leftVar.getResolvedType(), context.getType(float.class)) && !ElementUtils.typeEquals(leftVar.getResolvedType(), context.getType(double.class))) { return new BooleanLiteral(true); } } } } return super.visitBinary(binary); } }); Object o = reducedExpression.resolveConstant(); if (o instanceof Boolean) { if (((Boolean) o).booleanValue()) { return true; } } return false; } public boolean equalsNegated(GuardExpression other) { boolean negated = false; DSLExpression thisExpression = expression; if (thisExpression instanceof Negate) { negated = true; thisExpression = ((Negate) thisExpression).getReceiver(); } boolean otherNegated = false; DSLExpression otherExpression = other.expression; if (otherExpression instanceof Negate) { otherNegated = true; otherExpression = ((Negate) otherExpression).getReceiver(); } return Objects.equals(thisExpression, otherExpression) && negated != otherNegated; } public boolean implies(GuardExpression other) { if (Objects.equals(expression, other.expression)) { return true; } return false; } }