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