| /* |
| * Copyright 2008 Google Inc. |
| * |
| * Licensed 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 com.google.gwt.dev.jjs.impl.gflow.constants; |
| |
| import com.google.gwt.dev.jjs.ast.Context; |
| import com.google.gwt.dev.jjs.ast.JBinaryOperation; |
| import com.google.gwt.dev.jjs.ast.JBooleanLiteral; |
| import com.google.gwt.dev.jjs.ast.JDoubleLiteral; |
| import com.google.gwt.dev.jjs.ast.JExpression; |
| import com.google.gwt.dev.jjs.ast.JFloatLiteral; |
| import com.google.gwt.dev.jjs.ast.JLocalRef; |
| import com.google.gwt.dev.jjs.ast.JParameterRef; |
| import com.google.gwt.dev.jjs.ast.JValueLiteral; |
| import com.google.gwt.dev.jjs.ast.JVisitor; |
| import com.google.gwt.dev.jjs.ast.js.JMultiExpression; |
| |
| /** |
| * Assumption deducer analyzes the expression, knowing its value, and deduces |
| * variables constant values assumptions from it. |
| */ |
| final class AssumptionDeducer extends JVisitor { |
| /** |
| * Deduce assumptions, knowing that <code>expression</code> evaluates to |
| * <code>value</code> and stores individual variable assumptions in the |
| * <code>assumption</code> parameter. It will never override any existing |
| * constant assumptions. It will override top and bottom assumptions though. |
| */ |
| static void deduceAssumption( |
| JExpression expression, final JValueLiteral value, |
| final ConstantsAssumption.Updater assumption) { |
| new AssumptionDeducer(value, assumption).accept(expression); |
| } |
| private final ConstantsAssumption.Updater assumption; |
| |
| /** |
| * Contains the value of evaluating expression we're currently visiting. |
| * Is <code>null</code> if we do not know current expression value. |
| */ |
| private JValueLiteral currentValue; |
| |
| AssumptionDeducer(JValueLiteral value, ConstantsAssumption.Updater assumption) { |
| this.assumption = assumption; |
| currentValue = value; |
| } |
| |
| @SuppressWarnings("incomplete-switch") |
| @Override |
| public boolean visit(JBinaryOperation x, Context ctx) { |
| switch (x.getOp()) { |
| case EQ: |
| if (isTrue(currentValue)) { |
| if (x.getRhs() instanceof JValueLiteral && |
| isSubstitutableIfEquals(x.getRhs())) { |
| currentValue = (JValueLiteral) x.getRhs(); |
| accept(x.getLhs()); |
| return false; |
| } else if (x.getLhs() instanceof JValueLiteral && |
| isSubstitutableIfEquals(x.getLhs())) { |
| currentValue = (JValueLiteral) x.getLhs(); |
| accept(x.getRhs()); |
| return false; |
| } |
| } |
| break; |
| |
| case NEQ: |
| if (isFalse(currentValue)) { |
| if (x.getRhs() instanceof JValueLiteral && |
| isSubstitutableIfEquals(x.getRhs())) { |
| currentValue = (JValueLiteral) x.getRhs(); |
| accept(x.getLhs()); |
| return false; |
| } else if (x.getLhs() instanceof JValueLiteral && |
| isSubstitutableIfEquals(x.getLhs())) { |
| currentValue = (JValueLiteral) x.getLhs(); |
| accept(x.getRhs()); |
| return false; |
| } |
| } |
| break; |
| |
| case AND: |
| if (isTrue(currentValue)) { |
| accept(x.getLhs()); |
| currentValue = JBooleanLiteral.get(true); |
| accept(x.getRhs()); |
| return false; |
| } |
| break; |
| |
| case OR: |
| if (isFalse(currentValue)) { |
| accept(x.getLhs()); |
| currentValue = JBooleanLiteral.FALSE; |
| accept(x.getRhs()); |
| return false; |
| } |
| break; |
| } |
| currentValue = null; |
| return true; |
| } |
| |
| @Override |
| public boolean visit(JExpression x, Context ctx) { |
| // Unknown expression. Do not go inside. |
| return false; |
| } |
| |
| @Override |
| public boolean visit(JLocalRef x, Context ctx) { |
| if (assumption.hasAssumption(x.getTarget())) { |
| // Expression evaluation can't change existing assumptions |
| return false; |
| } |
| assumption.set(x.getTarget(), currentValue); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(JMultiExpression x, Context ctx) { |
| // Knowing the value multi expression, we know the value of its last |
| // expression only. |
| accept(x.exprs.get(x.exprs.size() - 1)); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(JParameterRef x, Context ctx) { |
| if (assumption.hasAssumption(x.getTarget())) { |
| // Expression evaluation shouldn't change existing assumptions |
| return false; |
| } |
| assumption.set(x.getTarget(), currentValue); |
| return false; |
| } |
| |
| private boolean isFalse(JValueLiteral value) { |
| return value instanceof JBooleanLiteral && |
| !((JBooleanLiteral) value).getValue(); |
| } |
| |
| /** |
| * Checks that if some expression equals <code>e</code>, then we can freely |
| * substitute it by e. |
| */ |
| private boolean isSubstitutableIfEquals(JExpression e) { |
| if (!(e instanceof JValueLiteral)) { |
| return false; |
| } |
| |
| if (e instanceof JFloatLiteral && |
| ((JFloatLiteral) e).getValue() == 0.0f) { |
| // There are +0.0 and -0.0. And both of them are equal. |
| // We can't substitute 0.0 instead of them. |
| return false; |
| } |
| |
| if (e instanceof JDoubleLiteral && |
| ((JDoubleLiteral) e).getValue() == 0.0d) { |
| // There are +0.0 and -0.0. And both of them are equal. |
| // We can't substitute 0.0 instead of them. |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private boolean isTrue(JValueLiteral value) { |
| return value instanceof JBooleanLiteral && |
| ((JBooleanLiteral) value).getValue(); |
| } |
| } |