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; }