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;
  }
 private static ArrayType getArrayType(final Type elementType) {
   if (elementType.isInteger()) {
     return Type.INT_ARRAY;
   } else if (elementType.isLong()) {
     return Type.LONG_ARRAY;
   } else if (elementType.isNumeric()) {
     return Type.NUMBER_ARRAY;
   } else {
     return Type.OBJECT_ARRAY;
   }
 }
 static Object computePresets(
     final Expression[] value, final Type elementType, final int[] postsets) {
   assert !elementType.isUnknown();
   if (elementType.isInteger()) {
     return presetIntArray(value, postsets);
   } else if (elementType.isLong()) {
     return presetLongArray(value, postsets);
   } else if (elementType.isNumeric()) {
     return presetDoubleArray(value, postsets);
   } else {
     return presetObjectArray(value, postsets);
   }
 }
  private static Type getPropertyType(final ScriptObject sobj, final String name) {
    final FindProperty find = sobj.findProperty(name, true);
    if (find == null) {
      return null;
    }

    final Property property = find.getProperty();
    final Class<?> propertyClass = property.getType();
    if (propertyClass == null) {
      // propertyClass == null means its value is Undefined. It is probably not initialized yet, so
      // we won't make
      // a type assumption yet.
      return null;
    } else if (propertyClass.isPrimitive()) {
      return Type.typeFor(propertyClass);
    }

    final ScriptObject owner = find.getOwner();
    if (property.hasGetterFunction(owner)) {
      // Can have side effects, so we can't safely evaluate it; since !propertyClass.isPrimitive(),
      // it's Object.
      return Type.OBJECT;
    }

    // Safely evaluate the property, and return the narrowest type for the actual value (e.g.
    // Type.INT for a boxed
    // integer).
    final Object value =
        property.needsDeclaration()
            ? ScriptRuntime.UNDEFINED
            : property.getObjectValue(owner, owner);
    if (value == ScriptRuntime.UNDEFINED) {
      return null;
    }
    return Type.typeFor(JSType.unboxedFieldType(value));
  }
      private static Type computeElementType(final Expression[] value) {
        Type widestElementType = Type.INT;

        for (final Expression elem : value) {
          if (elem == null) {
            widestElementType =
                widestElementType.widest(Type.OBJECT); // no way to represent undefined as number
            break;
          }

          final Type type = elem.getType().isUnknown() ? Type.OBJECT : elem.getType();
          if (type.isBoolean()) {
            // TODO fix this with explicit boolean types
            widestElementType = widestElementType.widest(Type.OBJECT);
            break;
          }

          widestElementType = widestElementType.widest(type);
          if (widestElementType.isObject()) {
            break;
          }
        }
        return widestElementType;
      }
 /**
  * Get the element type of this array literal
  *
  * @return element type
  */
 public Type getElementType() {
   assert !elementType.isUnknown() : this + " has elementType=unknown";
   return elementType;
 }
 @Override
 public Type getType() {
   return Type.typeFor(NativeArray.class);
 }
 @Override
 public Type getType() {
   return Type.typeFor(value.getClass());
 }
  private Type getEvaluatedType(final Optimistic expr) {
    if (expr instanceof IdentNode) {
      if (runtimeScope == null) {
        return null;
      }
      return getPropertyType(runtimeScope, ((IdentNode) expr).getName());
    } else if (expr instanceof AccessNode) {
      final AccessNode accessNode = (AccessNode) expr;
      final Object base = evaluateSafely(accessNode.getBase());
      if (!(base instanceof ScriptObject)) {
        return null;
      }
      return getPropertyType((ScriptObject) base, accessNode.getProperty());
    } else if (expr instanceof IndexNode) {
      final IndexNode indexNode = (IndexNode) expr;
      final Object base = evaluateSafely(indexNode.getBase());
      if (base instanceof NativeArray || base instanceof ArrayBufferView) {
        // NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of
        // their
        // underlying array storage, not based on values of individual elements. Thus, a
        // LongArrayData will
        // throw UOE for every optimistic int linkage attempt, even if the long value being returned
        // in the
        // first invocation would be representable as int. That way, we can presume that the array's
        // optimistic
        // type is the most optimistic type for which an element getter has a chance of executing
        // successfully.
        return ((ScriptObject) base).getArray().getOptimisticType();
      }
    } else if (expr instanceof CallNode) {
      // Currently, we'll only try to guess the return type of immediately invoked function
      // expressions with no
      // parameters, that is (function() { ... })(). We could do better, but these are all
      // heuristics and we can
      // gradually introduce them as needed. An easy one would be to do the same for .call(this)
      // idiom.
      final CallNode callExpr = (CallNode) expr;
      final Expression fnExpr = callExpr.getFunction();
      if (fnExpr instanceof FunctionNode) {
        final FunctionNode fn = (FunctionNode) fnExpr;
        if (callExpr.getArgs().isEmpty()) {
          final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(fn.getId());
          if (data != null) {
            final Type returnType =
                Type.typeFor(data.getReturnType(EMPTY_INVOCATION_TYPE, runtimeScope));
            if (returnType == Type.BOOLEAN) {
              // We don't have optimistic booleans. In fact, optimistic call sites getting back
              // boolean
              // currently deoptimize all the way to Object.
              return Type.OBJECT;
            }
            assert returnType == Type.INT
                || returnType == Type.LONG
                || returnType == Type.NUMBER
                || returnType == Type.OBJECT;
            return returnType;
          }
        }
      }
    }

    return null;
  }