private Object evaluateSafely(final Expression expr) { if (expr instanceof IdentNode) { return runtimeScope == null ? null : evaluatePropertySafely(runtimeScope, ((IdentNode) expr).getName()); } if (expr instanceof AccessNode) { final AccessNode accessNode = (AccessNode) expr; final Object base = evaluateSafely(accessNode.getBase()); if (!(base instanceof ScriptObject)) { return null; } return evaluatePropertySafely((ScriptObject) base, accessNode.getProperty()); } return null; }
@Override public boolean enterAccessNode(final AccessNode accessNode) { tagNeverOptimistic(accessNode.getBase()); return true; }
@Override public boolean enterAccessNode(final AccessNode accessNode) { curExpr = new MemberSelectTreeImpl(accessNode, translateExpr(accessNode.getBase())); return false; }
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; }