/* * Transfer functions */ public static Value evaluate( DOMObjects nativeObject, FunctionCalls.CallInfo call, State s, Solver.SolverInterface c) { switch (nativeObject) { case ACTIVE_X_OBJECT_OPEN: { NativeFunctions.expectParameters(nativeObject, call, c, 2, 5); /* Value method =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); /* Value url =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 1), c); return Value.makeUndef(); } case ACTIVE_X_OBJECT_SET_REQUEST_HEADER: { NativeFunctions.expectParameters(nativeObject, call, c, 2, 2); /* Value header =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); /* Value value =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 1), c); return Value.makeUndef(); } case ACTIVE_X_OBJECT_SEND: { NativeFunctions.expectParameters(nativeObject, call, c, 0, 1); return Value.makeUndef(); } case ACTIVE_X_OBJECT_ABORT: { NativeFunctions.expectParameters(nativeObject, call, c, 0, 0); return Value.makeUndef(); } case ACTIVE_X_OBJECT_GET_RESPONSE_HEADER: { NativeFunctions.expectParameters(nativeObject, call, c, 1, 1); /* Value header =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); return Value.makeAnyStr(); } case ACTIVE_X_OBJECT_GET_ALL_RESPONSE_HEADERS: { NativeFunctions.expectParameters(nativeObject, call, c, 0, 0); return Value.makeAnyStr(); } case ACTIVE_X_OBJECT_CONSTRUCTOR: { // TODO: Check if this is sound. return Value.makeObject(INSTANCES).joinUndef(); } default: { throw new AnalysisException("Unknown Native Object: " + nativeObject); } } }
/** 11.2.1 assignment with left-hand-side property accessor. */ @Override public void visit(WritePropertyNode n, State state) { // get the base value, coerce with ToObject Value baseval = state.readRegister(n.getBaseRegister()); baseval = UnknownValueResolver.getRealValue(baseval, state); m.visitPropertyAccess(n, baseval); Set<ObjectLabel> objlabels = Conversion.toObjectLabels(state, n, baseval, c); if (objlabels.isEmpty() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } state.writeRegister( n.getBaseRegister(), Value.makeObject(objlabels)); // if null/undefined, an exception would have been thrown via // toObjectLabels // get the property name value, separate the undefined/null/NaN components, coerce with ToString Value propertyval; int propertyreg; if (n.isPropertyFixed()) { propertyreg = AbstractNode.NO_VALUE; propertyval = Value.makeStr(n.getPropertyString()); } else { propertyreg = n.getPropertyRegister(); propertyval = state.readRegister(propertyreg); propertyval = UnknownValueResolver.getRealValue(propertyval, state); } boolean maybe_undef = propertyval.isMaybeUndef(); boolean maybe_null = propertyval.isMaybeNull(); boolean maybe_nan = propertyval.isMaybeNaN(); propertyval = propertyval.restrictToNotNullNotUndef().restrictToNotNaN(); Str propertystr = Conversion.toString(propertyval, propertyreg, c); // get the value to be written Value v = state.readRegister(n.getValueRegister()); NativeFunctions.updateArrayLength(n, state, objlabels, propertystr, v, n.getValueRegister(), c); // write the object property value, as fixed property name or unknown property name, and // separately for "undefined"/"null"/"NaN" state.writeProperty(objlabels, propertystr, v, true, maybe_undef || maybe_null || maybe_nan); if (maybe_undef && !propertystr.isMaybeStr("undefined")) state.writeProperty( objlabels, Value.makeTemporaryStr("undefined"), v, true, !propertystr.isNotStr()); if (maybe_null && !propertystr.isMaybeStr("null")) state.writeProperty( objlabels, Value.makeTemporaryStr("null"), v, true, !propertystr.isNotStr()); if (maybe_nan && !propertystr.isMaybeStr("NaN")) state.writeProperty( objlabels, Value.makeTemporaryStr("NaN"), v, true, !propertystr.isNotStr()); m.visitPropertyWrite(n, objlabels, propertystr); // TODO: more monitoring around here? if (Options.get().isEvalStatistics() && propertystr.getStr() != null && propertystr.getStr().equals("innerHTML")) { m.visitInnerHTMLWrite(n, v); } m.visitVariableOrProperty( n.getPropertyString(), n.getSourceLocation(), v, state.getContext(), state); }
/** 12.5 and 12.6 'if'/iteration statement. */ @Override public void visit(IfNode n, State state) { // do nothing (but see EdgeTransfer) Value val = state.readRegister(n.getConditionRegister()); val = UnknownValueResolver.getRealValue(val, state); m.visitIf(n, Conversion.toBoolean(val)); }
/** Assumption. */ @Override public void visit(AssumeNode n, State state) { if (Options.get().isControlSensitivityDisabled()) return; switch (n.getKind()) { case VARIABLE_NON_NULL_UNDEF: { Value v = state.readVariable(n.getVariableName(), null); v = UnknownValueResolver.getRealValue( v, state); // TODO: limits use of polymorphic values? v = v.restrictToNotNullNotUndef().restrictToNotAbsent(); if (v.isNotPresent() && !Options.get().isPropagateDeadFlow()) state.setToNone(); else state.writeVariable(n.getVariableName(), v, false); break; } case PROPERTY_NON_NULL_UNDEF: { String propname; if (n.isPropertyFixed()) propname = n.getPropertyString(); else { Value propval = state.readRegister(n.getPropertyRegister()); propval = UnknownValueResolver.getRealValue( propval, state); // TODO: limits use of polymorphic values? if (!propval.isMaybeSingleStr() || propval.isMaybeOtherThanStr()) break; // safe to do nothing here if it gets complicated propname = propval.getStr(); } Set<ObjectLabel> baseobjs = Conversion.toObjectLabels( state, n, state.readRegister(n.getBaseRegister()), null); // TODO: omitting side-effects here Value v = state.readPropertyWithAttributes(baseobjs, propname); if (v.isNotPresent() && !Options.get().isPropagateDeadFlow()) state.setToNone(); else if (baseobjs.size() == 1 && baseobjs.iterator().next().isSingleton()) { v = UnknownValueResolver.getRealValue( v, state); // TODO: limits use of polymorphic values? v = v.restrictToNotNullNotUndef().restrictToNotAbsent(); state.writePropertyWithAttributes(baseobjs, propname, v, false); } break; } case UNREACHABLE: { if (Options.get().isIgnoreUnreachableEnabled()) { state.setToNone(); } break; } default: throw new AnalysisException("Unhandled AssumeNode kind: " + n.getKind()); } }
/** 12.10 enter 'with' statement. */ @Override public void visit(BeginWithNode n, State state) { Value v = state.readRegister(n.getObjectRegister()); v = UnknownValueResolver.getRealValue(v, state); Set<ObjectLabel> objs = Conversion.toObjectLabels(state, n, v, c); if (objs.isEmpty() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } state.pushScopeChain(objs); }
/** 11.13 and 11.4.1 assignment with 'delete' operator. */ @Override public void visit(DeletePropertyNode n, State state) { Value v; if (n.isVariable()) { v = state.deleteVariable(n.getVariableName()); m.visitVariableOrProperty( n.getVariableName(), n.getSourceLocation(), v, state.getContext(), state); } else { Value baseval = state.readRegister(n.getBaseRegister()); baseval = UnknownValueResolver.getRealValue(baseval, state); m.visitPropertyAccess(n, baseval); if (baseval.isMaybeNull() || baseval.isMaybeUndef()) { Exceptions.throwTypeError(state, c); if (baseval.isNullOrUndef() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } } baseval = baseval.restrictToNotNullNotUndef(); state.writeRegister(n.getBaseRegister(), baseval); Set<ObjectLabel> objlabels = Conversion.toObjectLabels(state, n, baseval, c); if (objlabels.isEmpty() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } Str propertystr; if (n.isPropertyFixed()) { propertystr = Value.makeStr(n.getPropertyString()); } else { Value propertyval = state.readRegister(n.getPropertyRegister()); propertystr = Conversion.toString(propertyval, n.getPropertyRegister(), c); } v = state.deleteProperty(objlabels, propertystr, false); } if (v.isNotPresent() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } if (n.getResultRegister() != AbstractNode.NO_VALUE) state.writeRegister(n.getResultRegister(), v); }
/** Beginning of loop. */ @Override public void visit(BeginLoopNode n, State state) { // TODO: do nothing if loop unrolling is disabled or in scanning mode Value v = state.readRegister(n.getIfNode().getConditionRegister()); v = Conversion.toBoolean(UnknownValueResolver.getRealValue(v, state)); if (v.isMaybeTrueButNotFalse() || v.isMaybeFalseButNotTrue()) { // branch condition is determinate, switch context and propagate only to specialized successor Context specializedContext = c.getAnalysis() .getContextSensitivityStrategy() .makeNextLoopUnrollingContext(state.getContext(), n); BasicBlock successor = state.getBasicBlock().getSingleSuccessor(); State specializedState = state.clone(); specializedState.setContext(specializedContext); specializedState.setBasicBlock(successor); c.propagateToBasicBlock(specializedState, successor, specializedContext); state.setToNone(); } // otherwise, just ordinary propagation like no-op }
/** 12.6.4 begin 'for-in' statement. */ @Override public void visit(BeginForInNode n, State state) { if (!Options.get().isForInSpecializationDisabled()) { // 1. Find properties to iterate through Value v1 = state.readRegister(n.getObjectRegister()); state.writeRegister( n.getObjectRegister(), v1.makeExtendedScope()); // preserve the register value v1 = UnknownValueResolver.getRealValue(v1, state); Set<ObjectLabel> objs = Conversion.toObjectLabels(state, n, v1, c); State.Properties p = state.getEnumProperties(objs); Collection<Value> propertyNameValues = newList(p.toValues()); // Add the no-iteration case propertyNameValues.add(Value.makeNull().makeExtendedScope()); // 2. Make specialized context for each iteration int it = n.getPropertyListRegister(); // List<Context> specialized_contexts = newList(); BasicBlock successor = n.getBlock().getSingleSuccessor(); for (Value k : propertyNameValues) { m.visitPropertyRead(n, objs, k, state, true); if (!c.isScanning()) { // 2.1 Make specialized context State specialized_state = state.clone(); specialized_state.writeRegister(it, k); Context specialized_context = c.getAnalysis() .getContextSensitivityStrategy() .makeForInEntryContext(state.getContext(), n, k); // specialized_contexts.add(specialized_context); specialized_state.setContext(specialized_context); specialized_state.setBasicBlock(successor); // 2.2 Propagate specialized context c.propagateToFunctionEntry( n, state.getContext(), specialized_state, specialized_context, successor); } } if (!c.isScanning()) { // TODO: could kill flow to specializations if covered by other context // List<Context> previousSpecializations = c.getAnalysis().getForInSpecializations(n, // s.getContext()); // if (previousSpecializations != null && (p.isArray() || p.isNonArray())) { // previousSpecializations.forEach(c -> { // // covered.setToNone(); // }); // } // TODO: could kill null flow unless all iterations has reached at least one EndForInNode } state.setToNone(); } else { // fall back to simple mode without context specialization Value v1 = state.readRegister(n.getObjectRegister()); state.writeRegister( n.getObjectRegister(), v1.makeExtendedScope()); // preserve the register value v1 = UnknownValueResolver.getRealValue(v1, state); Set<ObjectLabel> objs = Conversion.toObjectLabels(state, n, v1, c); Properties p = state.getEnumProperties(objs); Value proplist = p.toValue().joinNull(); m.visitPropertyRead(n, objs, proplist, state, true); state.writeRegister(n.getPropertyListRegister(), proplist); } }
/** 11.2.2, 11.2.3, 13.2.1, and 13.2.2 'new' / function call. */ @Override public void visit(CallNode n, State state) { if (n.getFunctionRegister() != AbstractNode.NO_VALUE) // old style call (where the function is given as a variable read) FunctionCalls.callFunction( new OrdinaryCallInfo(n, state) { @Override public Value getFunctionValue() { Value functionValue = state.readRegister(n.getFunctionRegister()); if (n.getLiteralConstructorKind() != null) { // these literal invocations can not be spurious in ES5 switch (n.getLiteralConstructorKind()) { case ARRAY: functionValue = Value.makeObject(new ObjectLabel(ECMAScriptObjects.ARRAY, Kind.FUNCTION)); break; case REGEXP: functionValue = Value.makeObject(new ObjectLabel(ECMAScriptObjects.REGEXP, Kind.FUNCTION)); break; default: throw new AnalysisException( "Unhandled literal constructor type: " + n.getLiteralConstructorKind()); } } return functionValue; } @Override public Set<ObjectLabel> prepareThis(State caller_state, State callee_state) { return UserFunctionCalls.determineThis( n, caller_state, callee_state, c, n.getBaseRegister()); } }, state, c); else { // getPropertyString / getPropertyRegister - like ReadPropertyNode Value baseval = state.readRegister(n.getBaseRegister()); baseval = UnknownValueResolver.getRealValue(baseval, state); Set<ObjectLabel> objlabels = baseval.getObjectLabels(); // the ReadPropertyNode has updated baseval to account for // ToObject Value propertyval; int propertyreg; if (n.isPropertyFixed()) { propertyreg = AbstractNode.NO_VALUE; propertyval = Value.makeStr(n.getPropertyString()); } else { propertyreg = n.getPropertyRegister(); propertyval = state.readRegister(propertyreg); propertyval = UnknownValueResolver.getRealValue(propertyval, state); } boolean maybe_undef = propertyval.isMaybeUndef(); boolean maybe_null = propertyval.isMaybeNull(); boolean maybe_nan = propertyval.isMaybeNaN(); propertyval = propertyval.restrictToNotNullNotUndef().restrictToNotNaN(); Str propertystr = Conversion.toString(propertyval, propertyreg, c); // read the object property value, as fixed property name or unknown property name, and // separately for "undefined"/"null"/"NaN" Map<ObjectLabel, Set<ObjectLabel>> target2this = newMap(); List<Value> nonfunctions = newList(); for (ObjectLabel objlabel : objlabels) { // find possible targets for each possible base object Set<ObjectLabel> singleton = singleton(objlabel); Value v; boolean read_undefined = false; boolean read_null = false; boolean read_nan = false; if (propertystr.isMaybeSingleStr()) { String propertyname = propertystr.getStr(); v = state.readPropertyValue(singleton, propertyname); } else if (!propertystr.isNotStr()) { v = state.readPropertyValue(singleton, propertystr); read_undefined = propertystr.isMaybeStr("undefined"); read_null = propertystr.isMaybeStr("null"); read_nan = propertystr.isMaybeStr("NaN"); } else v = Value.makeNone(); if (maybe_undef && !read_undefined) { v = UnknownValueResolver.join(v, state.readPropertyValue(singleton, "undefined"), state); } if (maybe_null && !read_null) { v = UnknownValueResolver.join(v, state.readPropertyValue(singleton, "null"), state); } if (maybe_nan && !read_nan) { v = UnknownValueResolver.join(v, state.readPropertyValue(singleton, "NaN"), state); } v = UnknownValueResolver.getRealValue(v, state); // finally, remove all the TAJS hooks, which are spurious if accessed through a dynamic // property if (!n.isPropertyFixed()) { v = JSGlobal.removeTAJSSpecificFunctions(v); } for (ObjectLabel target : v.getObjectLabels()) { if (target.getKind() == Kind.FUNCTION) { addToMapSet(target2this, target, objlabel); } else { nonfunctions.add(Value.makeObject(target)); } } if (v.isMaybePrimitive()) { nonfunctions.add(v.restrictToNotObject()); } } // do calls to each target with the corresponding values of this for (Entry<ObjectLabel, Set<ObjectLabel>> me : target2this.entrySet()) { ObjectLabel target = me.getKey(); Set<ObjectLabel> this_objs = me.getValue(); FunctionCalls.callFunction( new OrdinaryCallInfo(n, state) { @Override public Value getFunctionValue() { return Value.makeObject(target); } @Override public Set<ObjectLabel> prepareThis(State caller_state, State callee_state) { return this_objs; } }, state, c); } // also model calls to non-function values FunctionCalls.callFunction( new OrdinaryCallInfo(n, state) { @Override public Value getFunctionValue() { return Value.join(nonfunctions); } @Override public Set<ObjectLabel> prepareThis(State caller_state, State callee_state) { return Collections.emptySet(); } }, state, c); } }
/** 11.2.1 assignment with right-hand-side property accessor. */ @Override public void visit(ReadPropertyNode n, State state) { // get the base value, coerce with ToObject Value baseval = state.readRegister(n.getBaseRegister()); baseval = UnknownValueResolver.getRealValue(baseval, state); m.visitPropertyAccess(n, baseval); Set<ObjectLabel> objlabels = Conversion.toObjectLabels(state, n, baseval, c); if (objlabels.isEmpty() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } state.writeRegister( n.getBaseRegister(), Value.makeObject(objlabels)); // if null/undefined, an exception would have been thrown via // toObjectLabels // get the property name value, separate the undefined/null/NaN components, coerce with ToString Value propertyval; int propertyreg; if (n.isPropertyFixed()) { propertyreg = AbstractNode.NO_VALUE; propertyval = Value.makeStr(n.getPropertyString()); } else { propertyreg = n.getPropertyRegister(); propertyval = state.readRegister(propertyreg); propertyval = UnknownValueResolver.getRealValue(propertyval, state); } boolean maybe_undef = propertyval.isMaybeUndef(); boolean maybe_null = propertyval.isMaybeNull(); boolean maybe_nan = propertyval.isMaybeNaN(); propertyval = propertyval.restrictToNotNullNotUndef().restrictToNotNaN(); Str propertystr = Conversion.toString(propertyval, propertyreg, c); // read the object property value, as fixed property name or unknown property name, and // separately for "undefined"/"null"/"NaN" Value v; boolean read_undefined = false; boolean read_null = false; boolean read_nan = false; if (propertystr.isMaybeSingleStr()) { String propertyname = propertystr.getStr(); m.visitReadProperty(n, objlabels, propertystr, maybe_undef || maybe_null || maybe_nan, state); v = state.readPropertyValue(objlabels, propertyname); m.visitPropertyRead(n, objlabels, propertystr, state, true); } else if (!propertystr.isNotStr()) { m.visitReadProperty(n, objlabels, propertystr, true, state); m.visitPropertyRead(n, objlabels, propertystr, state, true); v = state.readPropertyValue(objlabels, propertystr); read_undefined = propertystr.isMaybeStr("undefined"); read_null = propertystr.isMaybeStr("null"); read_nan = propertystr.isMaybeStr("NaN"); } else v = Value.makeNone(); if (maybe_undef && !read_undefined) { m.visitReadProperty(n, objlabels, Value.makeTemporaryStr("undefined"), true, state); v = UnknownValueResolver.join(v, state.readPropertyValue(objlabels, "undefined"), state); } if (maybe_null && !read_null) { m.visitReadProperty(n, objlabels, Value.makeTemporaryStr("null"), true, state); v = UnknownValueResolver.join(v, state.readPropertyValue(objlabels, "null"), state); } if (maybe_nan && !read_nan) { m.visitReadProperty(n, objlabels, Value.makeTemporaryStr("NaN"), true, state); v = UnknownValueResolver.join(v, state.readPropertyValue(objlabels, "NaN"), state); } // remove all the TAJS hooks, which are spurious if accessed through a dynamic property if (!n.isPropertyFixed()) { v = JSGlobal.removeTAJSSpecificFunctions(v); } m.visitVariableOrProperty( n.getPropertyString(), n.getSourceLocation(), v, state.getContext(), state); m.visitRead(n, v, state); if (v.isNotPresent() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } // store the resulting value if (n.getResultRegister() != AbstractNode.NO_VALUE) state.writeRegister(n.getResultRegister(), v); }
/** Transfer Functions. */ public static Value evaluate(DOMObjects nativeObject, CallInfo call, Solver.SolverInterface c) { State s = c.getState(); switch (nativeObject) { case ELEMENT_GET_ATTRIBUTE: { NativeFunctions.expectParameters(nativeObject, call, c, 1, 1); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); return Value.makeAnyStr(); } case ELEMENT_SET_ATTRIBUTE: { NativeFunctions.expectParameters(nativeObject, call, c, 2, 2); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); /* Value value =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 1), c); return Value.makeUndef(); } case ELEMENT_REMOVE_ATTRIBUTE: { NativeFunctions.expectParameters(nativeObject, call, c, 1, 1); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); return Value.makeUndef(); } case ELEMENT_GET_ATTRIBUTE_NS: { NativeFunctions.expectParameters(nativeObject, call, c, 2, 2); /* Value namespace =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 1), c); return Value.makeAnyStr(); } case ELEMENT_GET_ATTRIBUTE_NODE: { NativeFunctions.expectParameters(nativeObject, call, c, 1, 1); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); return Value.makeObject(DOMAttr.INSTANCES); } case ELEMENT_GET_ATTRIBUTE_NODE_NS: { NativeFunctions.expectParameters(nativeObject, call, c, 2, 2); /* Value namespace =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 1), c); return Value.makeObject(DOMAttr.INSTANCES); } case ELEMENT_GET_BOUNDING_CLIENT_RECT: { NativeFunctions.expectParameters(nativeObject, call, c, 0, 0); return Value.makeObject(ClientBoundingRect.INSTANCES); } case ELEMENT_GET_ELEMENTS_BY_TAGNAME: { // TODO: needs precision, but cannot do like document.getElementsByTagName() bc. State is // for everything NativeFunctions.expectParameters(nativeObject, call, c, 1, 1); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); return Value.makeObject(DOMNodeList.INSTANCES); } case ELEMENT_GET_ELEMENTS_BY_TAGNAME_NS: { NativeFunctions.expectParameters(nativeObject, call, c, 2, 2); /* Value namespace =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 1), c); return Value.makeObject(DOMNodeList.INSTANCES); } case ELEMENT_HAS_ATTRIBUTE: { NativeFunctions.expectParameters(nativeObject, call, c, 1, 1); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); return Value.makeAnyBool(); } case ELEMENT_HAS_ATTRIBUTE_NS: { NativeFunctions.expectParameters(nativeObject, call, c, 2, 2); /* Value namespace =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 1), c); return Value.makeAnyBool(); } case ELEMENT_REMOVE_ATTRIBUTE_NS: { NativeFunctions.expectParameters(nativeObject, call, c, 2, 2); /* Value namespaceURI =*/ Conversion.toString( NativeFunctions.readParameter(call, s, 0), c); /* Value localName =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 1), c); return Value.makeUndef(); } case ELEMENT_REMOVE_ATTRIBUTE_NODE: { NativeFunctions.expectParameters(nativeObject, call, c, 1, 1); return DOMConversion.toAttr(NativeFunctions.readParameter(call, s, 0), c); } case ELEMENT_SET_ATTRIBUTE_NS: { NativeFunctions.expectParameters(nativeObject, call, c, 3, 3); /* Value namespace =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c) .joinNull(); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 1), c); /* Value value =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 2), c); return Value.makeUndef(); } case ELEMENT_SET_ATTRIBUTE_NODE: { NativeFunctions.expectParameters(nativeObject, call, c, 1, 1); /* Value newAttr =*/ DOMConversion.toAttr(NativeFunctions.readParameter(call, s, 0), c); return Value.makeObject(DOMAttr.INSTANCES).joinNull(); } case ELEMENT_SET_ATTRIBUTE_NODE_NS: { NativeFunctions.expectParameters(nativeObject, call, c, 1, 1); /* Value newAttr =*/ DOMConversion.toAttr(NativeFunctions.readParameter(call, s, 0), c); return Value.makeObject(DOMAttr.INSTANCES).joinNull(); } case ELEMENT_SET_ID_ATTRIBUTE: { NativeFunctions.expectParameters(nativeObject, call, c, 2, 2); /* Value name =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); /* Value isId =*/ Conversion.toBoolean(NativeFunctions.readParameter(call, s, 1)); return Value.makeUndef(); } case ELEMENT_SET_ID_ATTRIBUTE_NS: { NativeFunctions.expectParameters(nativeObject, call, c, 3, 3); /* Value namespaceURI =*/ Conversion.toString( NativeFunctions.readParameter(call, s, 0), c); /* Value localName =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 1), c); /* Value isId =*/ Conversion.toBoolean(NativeFunctions.readParameter(call, s, 2)); return Value.makeUndef(); } case ELEMENT_SET_ID_ATTRIBUTE_NODE: { NativeFunctions.expectParameters(nativeObject, call, c, 2, 2); /* Value idAttr =*/ DOMConversion.toAttr(NativeFunctions.readParameter(call, s, 0), c); /* Value isId =*/ Conversion.toBoolean(NativeFunctions.readParameter(call, s, 1)); return Value.makeUndef(); } case ELEMENT_QUERY_SELECTOR_ALL: { NativeFunctions.expectParameters(nativeObject, call, c, 1, 1); return Value.makeObject(DOMNodeList.INSTANCES); } default: { throw new AnalysisException("Unknown Native Object: " + nativeObject); } } }
/** Evaluates the given native function. */ public static Value evaluate( ECMAScriptObjects nativeobject, CallInfo<? extends Node> call, State state, Solver.SolverInterface c) { if (NativeFunctions.throwTypeErrorIfConstructor(call, state, c)) return Value.makeBottom(new Dependency(), new DependencyGraphReference()); switch (nativeobject) { case MATH_ABS: // 15.8.2.1 case MATH_ASIN: // 15.8.2.3 case MATH_ACOS: // 15.8.2.2 case MATH_ATAN: // 15.8.2.4 case MATH_CEIL: // 15.8.2.6 case MATH_COS: // 15.8.2.7 case MATH_EXP: // 15.8.2.8 case MATH_FLOOR: // 15.8.2.9 case MATH_LOG: // 15.8.2.10 case MATH_ROUND: // 15.8.2.15 case MATH_SIN: // 15.8.2.16 case MATH_SQRT: // 15.8.2.17 case MATH_TAN: { // 15.8.2.18 // ################################################## Dependency dependency = new Dependency(); // ################################################## NativeFunctions.expectParameters(nativeobject, call, c, 1, 1); Value num = Conversion.toNumber(NativeFunctions.readParameter(call, 0), c); // ################################################## dependency.join(num.getDependency()); // ################################################## // ================================================== DependencyExpressionNode node = DependencyNode.link(Label.CALL, call.getSourceNode(), num, state); // ================================================== if (num.isMaybeSingleNum()) { double d = num.getNum(); double res; switch (nativeobject) { case MATH_ABS: res = Math.abs(d); break; case MATH_ASIN: res = Math.asin(d); break; case MATH_ACOS: res = Math.acos(d); break; case MATH_ATAN: res = Math.atan(d); break; case MATH_CEIL: res = Math.ceil(d); break; case MATH_COS: res = Math.cos(d); break; case MATH_EXP: res = Math.exp(d); break; case MATH_FLOOR: res = Math.floor(d); break; case MATH_LOG: res = Math.log(d); break; case MATH_ROUND: res = Math.round(d); break; case MATH_SIN: res = Math.sin(d); break; case MATH_SQRT: res = Math.sqrt(d); break; case MATH_TAN: res = Math.tan(d); break; default: throw new RuntimeException(); } return Value.makeNum(res, dependency, node.getReference()); } else if (!num.isNotNum()) return Value.makeAnyNum(dependency, node.getReference()); else return Value.makeBottom(dependency, node.getReference()); } case MATH_ATAN2: // 15.8.2.5 case MATH_POW: { // 15.8.2.13 // ################################################## Dependency dependency = new Dependency(); // ################################################## NativeFunctions.expectParameters(nativeobject, call, c, 2, 2); Value num1 = Conversion.toNumber(NativeFunctions.readParameter(call, 0), c); Value num2 = Conversion.toNumber(NativeFunctions.readParameter(call, 1), c); // ################################################## dependency.join(num1.getDependency()); dependency.join(num2.getDependency()); // ################################################## // ================================================== DependencyExpressionNode node = DependencyNode.link(Label.CALL, call.getSourceNode(), num1, num2, state); // ================================================== if (num1.isMaybeSingleNum() && num2.isMaybeSingleNum()) { double d1 = num1.getNum(); double d2 = num2.getNum(); double res; switch (nativeobject) { case MATH_ATAN2: res = Math.atan2(d1, d2); break; case MATH_POW: res = Math.pow(d1, d2); break; default: throw new RuntimeException(); } return Value.makeNum(res, dependency, node.getReference()); } else if (!num1.isNotNum() && !num2.isNotNum()) return Value.makeAnyNum(dependency, node.getReference()); else return Value.makeBottom(dependency, node.getReference()); } case MATH_MAX: { // 15.8.2.11 // ################################################## Dependency dependency = new Dependency(); // ################################################## // ================================================== DependencyExpressionNode node = DependencyNode.link(Label.CALL, call.getSourceNode(), state); // ================================================== double res = Double.NEGATIVE_INFINITY; if (call.isUnknownNumberOfArgs()) { Value num = Conversion.toNumber(NativeFunctions.readUnknownParameter(call), c); // ################################################## dependency.join(num.getDependency()); // ################################################## // ================================================== node.addParent(num.getDependencyGraphReference()); // ================================================== if (num.isMaybeSingleNum()) res = num.getNum(); else if (!num.isNotNum()) return Value.makeAnyNum(dependency, node.getReference()); else return Value.makeBottom(dependency, node.getReference()); } else for (int i = 0; i < call.getNumberOfArgs(); i++) { Value num = Conversion.toNumber(NativeFunctions.readParameter(call, i), c); // ################################################## dependency.join(num.getDependency()); // ################################################## // ================================================== node.addParent(num.getDependencyGraphReference()); // ================================================== if (num.isMaybeSingleNum()) res = Math.max(res, num.getNum()); else if (!num.isNotNum()) return Value.makeAnyNum(dependency, node.getReference()); else return Value.makeBottom(dependency, node.getReference()); } return Value.makeNum(res, dependency, node.getReference()); } case MATH_MIN: { // 15.8.2.12 // ################################################## Dependency dependency = new Dependency(); // ################################################## // ================================================== DependencyExpressionNode node = DependencyNode.link(Label.CALL, call.getSourceNode(), state); // ================================================== double res = Double.POSITIVE_INFINITY; if (call.isUnknownNumberOfArgs()) { Value num = Conversion.toNumber(NativeFunctions.readUnknownParameter(call), c); // ################################################## dependency.join(num.getDependency()); // ################################################## // ================================================== node.addParent(num.getDependencyGraphReference()); // ================================================== if (num.isMaybeSingleNum()) res = num.getNum(); else if (!num.isNotNum()) return Value.makeAnyNum(dependency, node.getReference()); else return Value.makeBottom(dependency, node.getReference()); } else for (int i = 0; i < call.getNumberOfArgs(); i++) { Value num = Conversion.toNumber(NativeFunctions.readParameter(call, i), c); // ################################################## dependency.join(num.getDependency()); // ################################################## // ================================================== node.addParent(num.getDependencyGraphReference()); // ================================================== if (num.isMaybeSingleNum()) res = Math.min(res, num.getNum()); else if (!num.isNotNum()) return Value.makeAnyNum(dependency, node.getReference()); else return Value.makeBottom(dependency, node.getReference()); } return Value.makeNum(res, dependency, node.getReference()); } case MATH_RANDOM: { // 15.8.2.14 // ################################################## Dependency dependency = new Dependency(); // ################################################## // ================================================== DependencyExpressionNode node = DependencyNode.link(Label.CALL, call.getSourceNode(), state); // ================================================== NativeFunctions.expectParameters(nativeobject, call, c, 0, 0); return Value.makeAnyNumNotNaNInf(dependency, node.getReference()); } default: return null; } }
public static Value evaluate( DOMObjects nativeObject, FunctionCalls.CallInfo call, State s, Solver.SolverInterface c) { switch (nativeObject) { case MOUSE_EVENT_INIT_MOUSE_EVENT: { NativeFunctions.expectParameters(nativeObject, call, c, 15, 15); /* Value typeArg =*/ Conversion.toString(NativeFunctions.readParameter(call, s, 0), c); /* Value canBubbleArg =*/ Conversion.toBoolean(NativeFunctions.readParameter(call, s, 1)); /* Value cancelableArg =*/ Conversion.toBoolean( NativeFunctions.readParameter(call, s, 2)); // View arg not checked /* Value detailArg =*/ Conversion.toNumber(NativeFunctions.readParameter(call, s, 4), c); /* Value screenXArg =*/ Conversion.toNumber(NativeFunctions.readParameter(call, s, 5), c); /* Value screenYArg =*/ Conversion.toNumber(NativeFunctions.readParameter(call, s, 6), c); /* Value clientXArg =*/ Conversion.toNumber(NativeFunctions.readParameter(call, s, 7), c); /* Value clientYArg =*/ Conversion.toNumber(NativeFunctions.readParameter(call, s, 8), c); /* Value ctrlKeyArg =*/ Conversion.toBoolean(NativeFunctions.readParameter(call, s, 9)); /* Value altKeyArg =*/ Conversion.toBoolean(NativeFunctions.readParameter(call, s, 10)); /* Value shiftKeyArg =*/ Conversion.toBoolean(NativeFunctions.readParameter(call, s, 11)); /* Value metaKeyArg =*/ Conversion.toBoolean(NativeFunctions.readParameter(call, s, 12)); /* Value buttonArg =*/ Conversion.toNumber(NativeFunctions.readParameter(call, s, 13), c); /* Value relatedTargetArg =*/ DOMConversion.toEventTarget( NativeFunctions.readParameter(call, s, 14), c); return Value.makeUndef(); } default: throw new UnsupportedOperationException("Unsupported Native Object: " + nativeObject); } }