private Expression leaveOptimistic(final Optimistic opt) {
   final int pp = opt.getProgramPoint();
   if (isValid(pp) && !neverOptimistic.peek().get(pp)) {
     return (Expression) opt.setType(compiler.getOptimisticType(opt));
   }
   return (Expression) opt;
 }
  Type getOptimisticType(final Optimistic node) {
    assert compiler.useOptimisticTypes();

    final int programPoint = node.getProgramPoint();
    final Type validType = compiler.getInvalidatedProgramPointType(programPoint);

    if (validType != null) {
      return validType;
    }

    final Type mostOptimisticType = node.getMostOptimisticType();
    final Type evaluatedType = getEvaluatedType(node);

    if (evaluatedType != null) {
      if (evaluatedType.widerThan(mostOptimisticType)) {
        final Type newValidType =
            evaluatedType.isObject() || evaluatedType.isBoolean() ? Type.OBJECT : evaluatedType;
        // Update invalidatedProgramPoints so we don't re-evaluate the expression next time. This is
        // a heuristic
        // as we're doing a tradeoff. Re-evaluating expressions on each recompile takes time, but it
        // might
        // notice a widening in the type of the expression and thus prevent an unnecessary
        // deoptimization later.
        // We'll presume though that the types of expressions are mostly stable, so if we evaluated
        // it in one
        // compilation, we'll keep to that and risk a low-probability deoptimization if its type
        // gets widened
        // in the future.
        compiler.addInvalidatedProgramPoint(node.getProgramPoint(), newValidType);
      }
      return evaluatedType;
    }
    return mostOptimisticType;
  }