/** * Converts the given value to the given NativeObject (optionally following the prototype chains). * * @param nativeObject target NativeObject * @param value Value to convert * @param prototype use the prototype chain? */ public static Value toNativeObject( HostObject nativeObject, Value value, boolean prototype, Solver.SolverInterface solverInterface) { State state = solverInterface.getState(); boolean bad = false; Set<ObjectLabel> matches = Collections.newSet(); if (prototype) { // Make lookup using prototype chains Set<ObjectLabel> objectLabels = Collections.newSet(value.getObjectLabels()); Set<ObjectLabel> visited = Collections.newSet(); while (!objectLabels.isEmpty()) { Set<ObjectLabel> temp = Collections.newSet(); for (ObjectLabel objectLabel : objectLabels) { if (!visited.contains(objectLabel)) { visited.add(objectLabel); Value prototypeValue = state.readInternalPrototype(java.util.Collections.singleton(objectLabel)); prototypeValue = UnknownValueResolver.getRealValue(prototypeValue, state); // FIXME: Needs code review. Looks fishy to compare objects with toString(). String nativeObjectPrototype = nativeObject.toString(); String objectLabelPrototype = ""; if (objectLabel.getHostObject() != null) { objectLabelPrototype = objectLabel.getHostObject().toString(); } if (nativeObject == objectLabel.getHostObject() || nativeObjectPrototype.equals(objectLabelPrototype)) { matches.add(objectLabel); } else if (prototypeValue.getObjectLabels().isEmpty()) { bad = true; } else { temp.addAll(prototypeValue.getObjectLabels()); } } } objectLabels = temp; } } else { // Make lookup ignoring prototype chains // TODO: Verify this for (ObjectLabel objectLabel : value.getObjectLabels()) { if (objectLabel.getHostObject() == nativeObject || (objectLabel.getHostObject() != null && objectLabel.getHostObject().toString().equals(nativeObject + ".prototype"))) { matches.add(objectLabel); } else { bad = true; } } } // Message.Status status; // if (good && bad) { // status = Message.Status.MAYBE; // } else if (!good && bad) { // status = Message.Status.CERTAIN; // } else if (good && !bad) { // status = Message.Status.NONE; // } else if (!good && !bad) { // equivalent to Value of Undef / a null argument // // Considered a certain type error. // status = Message.Status.CERTAIN; // } else { // throw new AnalysisException("toNativeObject: fell through cases - should not // happen."); // } if (bad) { String message = "TypeError, argument is not of expected type: " + nativeObject; solverInterface .getMonitoring() .addMessage(solverInterface.getNode(), Message.Severity.HIGH, message); } return Value.makeObject(matches); }
/** 11.13 and 11.4 assignment with unary operator. */ @Override public void visit(UnaryOperatorNode n, State state) { Value arg = state.readRegister(n.getArgRegister()); arg = UnknownValueResolver.getRealValue(arg, state); Value v; switch (n.getOperator()) { case COMPLEMENT: v = Operators.complement(arg, n.getArgRegister(), c); break; case MINUS: v = Operators.uminus(arg, n.getArgRegister(), c); break; case NOT: v = Operators.not(arg, c); break; case PLUS: v = Operators.uplus(arg, n.getArgRegister(), c); break; default: throw new AnalysisException(); } if (v.isNotPresent() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } if (n.getResultRegister() != AbstractNode.NO_VALUE) state.writeRegister(n.getResultRegister(), v); }
/** 11.13 and 7.8 assignment with literal. */ @Override public void visit(ConstantNode n, State state) { Value v; switch (n.getType()) { case NULL: v = Value.makeNull(); break; case UNDEFINED: v = Value.makeUndef(); break; case BOOLEAN: v = Value.makeBool(n.getBoolean()); break; case NUMBER: v = Value.makeNum(n.getNumber()); break; case STRING: v = Value.makeStr(n.getString()); break; default: throw new AnalysisException(); } if (n.getResultRegister() != AbstractNode.NO_VALUE) state.writeRegister(n.getResultRegister(), v); }
/** 12.14 'catch' block. */ @Override public void visit(CatchNode n, State state) { Value v = state.readRegister(AbstractNode.EXCEPTION_REG); state.removeRegister(AbstractNode.EXCEPTION_REG); if (n.getValueRegister() != AbstractNode.NO_VALUE) { state.writeRegister(n.getValueRegister(), v.makeExtendedScope()); } else { ObjectLabel objlabel = new ObjectLabel(n, Kind.OBJECT); state.newObject(objlabel); state.writeInternalPrototype( objlabel, Value.makeObject(InitialStateBuilder.OBJECT_PROTOTYPE)); state.writePropertyWithAttributes( objlabel, n.getVariableName(), v.setAttributes(false, true, false)); state.writeRegister(n.getScopeObjRegister(), Value.makeObject(objlabel)); /* From ES5, Annex D: In Edition 3, an object is created, as if by new Object() to serve as the scope for resolving the name of the exception parameter passed to a catch clause of a try statement. If the actual exception object is a function and it is called from within the catch clause, the scope object will be passed as the this value of the call. The body of the function can then define new properties on its this value and those property names become visible identifiers bindings within the scope of the catch clause after the function returns. In Edition 5, when an exception parameter is called as a function, undefined is passed as the this value. */ // TODO: use ES5 semantics of catch object? } }
/** 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()); } }
/** 11.1.5 object initializer. */ @Override public void visit(NewObjectNode n, State state) { HeapContext heapContext = c.getAnalysis().getContextSensitivityStrategy().makeObjectLiteralHeapContext(n, state); ObjectLabel objlabel = new ObjectLabel(n, Kind.OBJECT, heapContext); state.newObject(objlabel); state.writeInternalPrototype(objlabel, Value.makeObject(InitialStateBuilder.OBJECT_PROTOTYPE)); if (n.getResultRegister() != AbstractNode.NO_VALUE) state.writeRegister(n.getResultRegister(), Value.makeObject(objlabel)); }
/** 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.6.4 get next property of 'for-in' statement. */ @Override public void visit(NextPropertyNode n, State state) { Value property_name = state .readRegister(n.getPropertyListRegister()) .restrictToStr(); // restrictToStr to remove Null (the end-of-list marker) if (property_name.isNone()) { // possible if branch pruning in EdgeTransfer is disabled state.setToNone(); return; } state.writeRegister(n.getPropertyRegister(), property_name); }
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); } }
/** 11.1.2 assignment with right-hand-side identifier reference. */ @Override public void visit(ReadVariableNode n, State state) { String varname = n.getVariableName(); Value v; if (varname.equals("this")) { // 11.1.1 read 'this' from the execution context v = state.readThis(); m.visitReadThis(n, v, state, InitialStateBuilder.GLOBAL); } else { // ordinary variable int result_base_reg = n.getResultBaseRegister(); Set<ObjectLabel> base_objs = null; if (c.isScanning() || result_base_reg != AbstractNode.NO_VALUE) base_objs = newSet(); v = state.readVariable(varname, base_objs); m.visitPropertyRead(n, base_objs, Value.makeTemporaryStr(varname), state, true); m.visitVariableAsRead(n, v, state); m.visitVariableOrProperty(varname, n.getSourceLocation(), v, state.getContext(), state); m.visitReadNonThisVariable(n, v); if (v.isMaybeAbsent()) Exceptions.throwReferenceError(state, c); if (v.isNotPresent() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } if (result_base_reg != AbstractNode.NO_VALUE) state.writeRegister(result_base_reg, Value.makeObject(base_objs)); // see 10.1.4 m.visitRead(n, v, state); m.visitReadVariable(n, v, state); // TODO: combine some of these m.visitXYZ methods? } if (v.isNotPresent() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } if (n.getResultRegister() != AbstractNode.NO_VALUE) state.writeRegister(n.getResultRegister(), v.restrictToNotAbsent()); }
public static void build(State s) { DOMNodeList.build(s); DOMNode.build(s); DOMAttr.build(s); DOMNamedNodeMap.build(s); DOMDocumentType.build(s); DOMException.build(s); DOMElement.build(s); DOMCharacterData.build(s); DOMText.build(s); DOMConfiguration.build(s); DOMNotation.build(s); DOMCDataSection.build(s); DOMComment.build(s); DOMEntity.build(s); DOMEntityReference.build(s); DOMProcessingInstruction.build(s); DOMStringList.build(s); DOMDocumentFragment.build(s); // Document DOMDocument.build(s); DOMImplementation.build(s); // Set the remaining properties on DOMNode, due to circularity, and // summarize. createDOMProperty( s, DOMNode.PROTOTYPE, "attributes", Value.makeObject( DOMNamedNodeMap.INSTANCES, new Dependency(), new DependencyGraphReference()), DOMSpec.LEVEL_1); createDOMProperty( s, DOMNode.PROTOTYPE, "ownerDocument", Value.makeObject(DOMDocument.INSTANCES, new Dependency(), new DependencyGraphReference()), DOMSpec.LEVEL_1); s.multiplyObject(DOMNode.INSTANCES); DOMNode.INSTANCES = DOMNode.INSTANCES.makeSingleton().makeSummary(); }
/** 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 }
public static void build(Solver.SolverInterface c) { State s = c.getState(); PropVarOperations pv = c.getAnalysis().getPropVarOperations(); CONSTRUCTOR = new ObjectLabel(DOMObjects.HTMLHRELEMENT_CONSTRUCTOR, ObjectLabel.Kind.FUNCTION); PROTOTYPE = new ObjectLabel(DOMObjects.HTMLHRELEMENT_PROTOTYPE, ObjectLabel.Kind.OBJECT); INSTANCES = new ObjectLabel(DOMObjects.HTMLHRELEMENT_INSTANCES, ObjectLabel.Kind.OBJECT); // Constructor Object s.newObject(CONSTRUCTOR); pv.writePropertyWithAttributes( CONSTRUCTOR, "length", Value.makeNum(0).setAttributes(true, true, true)); pv.writePropertyWithAttributes( CONSTRUCTOR, "prototype", Value.makeObject(PROTOTYPE).setAttributes(true, true, true)); s.writeInternalPrototype(CONSTRUCTOR, Value.makeObject(InitialStateBuilder.FUNCTION_PROTOTYPE)); pv.writeProperty(DOMWindow.WINDOW, "HTMLHRElement", Value.makeObject(CONSTRUCTOR)); // Prototype Object s.newObject(PROTOTYPE); s.writeInternalPrototype(PROTOTYPE, Value.makeObject(HTMLElement.ELEMENT_PROTOTYPE)); // Multiplied Object s.newObject(INSTANCES); s.writeInternalPrototype(INSTANCES, Value.makeObject(PROTOTYPE)); /* * Properties. */ // DOM Level 1 createDOMProperty(INSTANCES, "align", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "noShade", Value.makeAnyBool(), c); createDOMProperty(INSTANCES, "size", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "width", Value.makeAnyStr(), c); s.multiplyObject(INSTANCES); INSTANCES = INSTANCES.makeSingleton().makeSummary(); /* * Functions. */ // No functions. }
/* * 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); } } }
/** * Transfer for a return statement. * * @param caller if non-null, only consider this caller */ public void transferReturn( int valueReg, BasicBlock block, State state, NodeAndContext<Context> caller, Context edge_context) { Value v; if (valueReg != AbstractNode.NO_VALUE) v = state.readRegister(valueReg); else v = Value.makeUndef(); UserFunctionCalls.leaveUserFunction( v, false, block.getFunction(), state, c, caller, edge_context); }
/** 12.6.4 check for more properties of 'for-in' statement. */ @Override public void visit(HasNextPropertyNode n, State state) { Value v = UnknownValueResolver.getRealValue(state.readRegister(n.getPropertyListRegister()), state); Value res = !v.isNotStr() ? Value.makeBool(true) : Value.makeNone(); // string values represent property names if (v.isMaybeNull()) // null marks end-of-list res = res.joinBool(false); state.writeRegister(n.getResultRegister(), res); }
/** 11.13 and 11.1.2 assignment with left-hand-side identifier reference. */ @Override public void visit(WriteVariableNode n, State state) { Value v = state.readRegister(n.getValueRegister()); m.visitWriteVariable(n, v, state); Set<ObjectLabel> objs = state.writeVariable(n.getVariableName(), v, true); Function f = n.getBlock().getFunction(); if (f.getParameterNames().contains(n.getVariableName())) { // TODO: review ObjectLabel arguments_obj = new ObjectLabel(f.getEntry().getFirstNode(), Kind.ARGUMENTS); state.writeProperty( arguments_obj, Integer.toString(f.getParameterNames().indexOf(n.getVariableName())), v); } m.visitPropertyWrite(n, objs, Value.makeTemporaryStr(n.getVariableName())); m.visitVariableOrProperty( n.getVariableName(), n.getSourceLocation(), v, state.getContext(), state); }
/** 11.13 and 11.4.3 assignment with 'typeof' operator. */ @Override public void visit(TypeofNode n, State state) { Value v; if (n.isVariable()) { Value val = state.readVariable( n.getVariableName(), null); // TODO: should also count as a variable read in Monitoring? val = UnknownValueResolver.getRealValue(val, state); v = Operators.typeof(val, val.isMaybeAbsent()); m.visitVariableOrProperty( n.getVariableName(), n.getOperandSourceLocation(), val, state.getContext(), state); } else { Value val = state.readRegister(n.getArgRegister()); val = UnknownValueResolver.getRealValue(val, state); v = Operators.typeof(val, false); } if (v.isNotPresent() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } if (n.getResultRegister() != AbstractNode.NO_VALUE) state.writeRegister(n.getResultRegister(), v); }
/** 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); }
public static void build(State s) { CONSTRUCTOR = new ObjectLabel(DOMObjects.HTMLBASEELEMENT_CONSTRUCTOR, ObjectLabel.Kind.FUNCTION); PROTOTYPE = new ObjectLabel(DOMObjects.HTMLBASEELEMENT_PROTOTYPE, ObjectLabel.Kind.OBJECT); INSTANCES = new ObjectLabel(DOMObjects.HTMLBASEELEMENT_INSTANCES, ObjectLabel.Kind.OBJECT); // Constructor Object s.newObject(CONSTRUCTOR); s.writePropertyWithAttributes( CONSTRUCTOR, "length", Value.makeNum(0).setAttributes(true, true, true)); s.writePropertyWithAttributes( CONSTRUCTOR, "prototype", Value.makeObject(PROTOTYPE).setAttributes(true, true, true)); s.writeInternalPrototype(CONSTRUCTOR, Value.makeObject(InitialStateBuilder.OBJECT_PROTOTYPE)); s.writeProperty(DOMWindow.WINDOW, "HTMLBaseElement", Value.makeObject(CONSTRUCTOR)); // Prototype Object s.newObject(PROTOTYPE); s.writeInternalPrototype(PROTOTYPE, Value.makeObject(HTMLElement.ELEMENT_PROTOTYPE)); // Multiplied Object s.newObject(INSTANCES); s.writeInternalPrototype(INSTANCES, Value.makeObject(PROTOTYPE)); /* * Properties. */ // DOM LEVEL 1 createDOMProperty(s, INSTANCES, "href", Value.makeAnyStr()); createDOMProperty(s, INSTANCES, "target", Value.makeAnyStr()); s.multiplyObject(INSTANCES); INSTANCES = INSTANCES.makeSingleton().makeSummary(); /* * Functions. */ // No functions. }
public static void build(Solver.SolverInterface c) { State s = c.getState(); PropVarOperations pv = c.getAnalysis().getPropVarOperations(); CONSTRUCTOR = new ObjectLabel(DOMObjects.COMMENT_CONSTRUCTOR, ObjectLabel.Kind.FUNCTION); PROTOTYPE = new ObjectLabel(DOMObjects.COMMENT_PROTOTYPE, ObjectLabel.Kind.OBJECT); INSTANCES = new ObjectLabel(DOMObjects.COMMENT_INSTANCES, ObjectLabel.Kind.OBJECT); // Constructor Object s.newObject(CONSTRUCTOR); pv.writePropertyWithAttributes( CONSTRUCTOR, "length", Value.makeNum(0).setAttributes(true, true, true)); pv.writePropertyWithAttributes( CONSTRUCTOR, "prototype", Value.makeObject(PROTOTYPE).setAttributes(true, true, true)); s.writeInternalPrototype(CONSTRUCTOR, Value.makeObject(InitialStateBuilder.OBJECT_PROTOTYPE)); pv.writeProperty(DOMWindow.WINDOW, "Comment", Value.makeObject(CONSTRUCTOR)); // Prototype object. s.newObject(PROTOTYPE); s.writeInternalPrototype(PROTOTYPE, Value.makeObject(DOMCharacterData.PROTOTYPE)); // Multiplied object. s.newObject(INSTANCES); s.writeInternalPrototype(INSTANCES, Value.makeObject(PROTOTYPE)); s.multiplyObject(INSTANCES); INSTANCES = INSTANCES.makeSingleton().makeSummary(); /* * Properties. */ // No properties. /* * Functions. */ // No functions. }
public static void build(Solver.SolverInterface c) { State s = c.getState(); PropVarOperations pv = c.getAnalysis().getPropVarOperations(); CONSTRUCTOR = new ObjectLabel(DOMObjects.HTMLOBJECTELEMENT_CONSTRUCTOR, ObjectLabel.Kind.FUNCTION); PROTOTYPE = new ObjectLabel(DOMObjects.HTMLOBJECTELEMENT_PROTOTYPE, ObjectLabel.Kind.OBJECT); INSTANCES = new ObjectLabel(DOMObjects.HTMLOBJECTELEMENT_INSTANCES, ObjectLabel.Kind.OBJECT); // Constructor Object s.newObject(CONSTRUCTOR); pv.writePropertyWithAttributes( CONSTRUCTOR, "length", Value.makeNum(0).setAttributes(true, true, true)); pv.writePropertyWithAttributes( CONSTRUCTOR, "prototype", Value.makeObject(PROTOTYPE).setAttributes(true, true, true)); s.writeInternalPrototype(CONSTRUCTOR, Value.makeObject(InitialStateBuilder.FUNCTION_PROTOTYPE)); pv.writeProperty(DOMWindow.WINDOW, "HTMLObjectElement", Value.makeObject(CONSTRUCTOR)); // Prototype Object s.newObject(PROTOTYPE); s.writeInternalPrototype(PROTOTYPE, Value.makeObject(HTMLElement.ELEMENT_PROTOTYPE)); // Multiplied Object s.newObject(INSTANCES); s.writeInternalPrototype(INSTANCES, Value.makeObject(PROTOTYPE)); /* * Properties. */ // DOM Level 1 createDOMProperty( INSTANCES, "form", Value.makeObject(HTMLFormElement.INSTANCES).setReadOnly(), c); createDOMProperty(INSTANCES, "code", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "align", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "archive", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "border", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "codeBase", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "codeType", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "data", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "declare", Value.makeAnyBool(), c); createDOMProperty(INSTANCES, "height", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "hspace", Value.makeAnyNum(), c); createDOMProperty(INSTANCES, "name", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "standby", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "tabIndex", Value.makeAnyNum(), c); createDOMProperty( INSTANCES, "type", Value.makeAnyStr().restrictToNotStrIdentifierParts() /* mime-type */, c); createDOMProperty(INSTANCES, "useMap", Value.makeAnyStr(), c); createDOMProperty(INSTANCES, "vspace", Value.makeAnyNum(), c); createDOMProperty(INSTANCES, "width", Value.makeAnyStr(), c); // DOM Level 2 createDOMProperty( INSTANCES, "contentDocument", Value.makeObject(DOMDocument.INSTANCES).setReadOnly(), c); s.multiplyObject(INSTANCES); INSTANCES = INSTANCES.makeSingleton().makeSummary(); /* * Functions. */ // No functions. }
/** 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; } }
/** 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); } } }
/** 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); } }
public static void build(Solver.SolverInterface c) { State s = c.getState(); PropVarOperations pv = c.getAnalysis().getPropVarOperations(); CONSTRUCTOR = new ObjectLabel(DOMObjects.ELEMENT_CONSTRUCTOR, ObjectLabel.Kind.FUNCTION); PROTOTYPE = new ObjectLabel(DOMObjects.ELEMENT_PROTOTYPE, ObjectLabel.Kind.OBJECT); INSTANCES = new ObjectLabel(DOMObjects.ELEMENT_INSTANCES, ObjectLabel.Kind.OBJECT); // Constructor Object s.newObject(CONSTRUCTOR); pv.writePropertyWithAttributes( CONSTRUCTOR, "length", Value.makeNum(0).setAttributes(true, true, true)); pv.writePropertyWithAttributes( CONSTRUCTOR, "prototype", Value.makeObject(PROTOTYPE).setAttributes(true, true, true)); s.writeInternalPrototype(CONSTRUCTOR, Value.makeObject(InitialStateBuilder.OBJECT_PROTOTYPE)); pv.writeProperty(DOMWindow.WINDOW, "Element", Value.makeObject(CONSTRUCTOR)); // Prototype s.newObject(PROTOTYPE); s.writeInternalPrototype(PROTOTYPE, Value.makeObject(DOMNode.PROTOTYPE)); // Multiplied object s.newObject(INSTANCES); s.writeInternalPrototype(INSTANCES, Value.makeObject(PROTOTYPE)); /* * Properties. */ // DOM Level 1 createDOMProperty(INSTANCES, "tagName", Value.makeAnyStr(), c); s.multiplyObject(INSTANCES); INSTANCES = INSTANCES.makeSingleton().makeSummary(); /* * Functions. */ // Unknown createDOMFunction( PROTOTYPE, DOMObjects.ELEMENT_GET_BOUNDING_CLIENT_RECT, "getBoundingClientRect", 0, c); // DOM Level 1 createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_GET_ATTRIBUTE, "getAttribute", 1, c); createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_SET_ATTRIBUTE, "setAttribute", 2, c); createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_REMOVE_ATTRIBUTE, "removeAttribute", 1, c); createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_GET_ATTRIBUTE_NODE, "getAttributeNode", 1, c); createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_SET_ATTRIBUTE_NODE, "setAttributeNode", 2, c); createDOMFunction( PROTOTYPE, DOMObjects.ELEMENT_REMOVE_ATTRIBUTE_NODE, "removeAttributeNode", 1, c); createDOMFunction( PROTOTYPE, DOMObjects.ELEMENT_GET_ELEMENTS_BY_TAGNAME, "getElementsByTagName", 1, c); // DOM Level 2 createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_GET_ATTRIBUTE_NS, "getAttributeNS", 2, c); createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_SET_ATTRIBUTE_NS, "setAttributeNS", 3, c); createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_REMOVE_ATTRIBUTE_NS, "removeAttributeNS", 2, c); createDOMFunction( PROTOTYPE, DOMObjects.ELEMENT_GET_ATTRIBUTE_NODE_NS, "getAttributeNodeNS", 2, c); createDOMFunction( PROTOTYPE, DOMObjects.ELEMENT_SET_ATTRIBUTE_NODE_NS, "setAttributeNodeNS", 3, c); createDOMFunction( PROTOTYPE, DOMObjects.ELEMENT_GET_ELEMENTS_BY_TAGNAME_NS, "getElementsByTagNameNS", 2, c); createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_HAS_ATTRIBUTE, "hasAttribute", 1, c); createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_HAS_ATTRIBUTE_NS, "hasAttributeNS", 2, c); // DOM Level 3 createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_SET_ID_ATTRIBUTE, "setIdAttribute", 2, c); createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_SET_ID_ATTRIBUTE_NS, "setIdAttributeNS", 3, c); createDOMFunction( PROTOTYPE, DOMObjects.ELEMENT_SET_ID_ATTRIBUTE_NODE, "setIdAttributeNode", 2, c); // DOM Level 2 createDOMProperty( DOMAttr.INSTANCES, "ownerElement", Value.makeObject(INSTANCES).setReadOnly(), c); // semistandard createDOMFunction(PROTOTYPE, DOMObjects.ELEMENT_QUERY_SELECTOR_ALL, "querySelectorAll", 1, c); }
/** 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); } }
/** 12.2 variable declaration. */ @Override public void visit(DeclareVariableNode n, State state) { state.declareAndWriteVariable(n.getVariableName(), Value.makeUndef(), false); }
/** 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); }
/** 11.13 and 11.5/6/7/8 assignment with binary operator. */ @Override public void visit(BinaryOperatorNode n, State state) { Value arg1 = state.readRegister(n.getArg1Register()); Value arg2 = state.readRegister(n.getArg2Register()); arg1 = UnknownValueResolver.getRealValue(arg1, state); arg2 = UnknownValueResolver.getRealValue(arg2, state); Value v; switch (n.getOperator()) { case ADD: v = Operators.add( arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); // TODO: test07.js could improve messages if keeping conversions of the two args // separate break; case AND: v = Operators.and(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case DIV: v = Operators.div(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case EQ: v = Operators.eq(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case GE: v = Operators.ge(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case GT: v = Operators.gt(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case IN: v = Operators.in(state, arg1, n.getArg1Register(), arg2, c); break; case INSTANCEOF: v = Operators.instof(state, arg1, arg2, c); break; case LE: v = Operators.le(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case LT: v = Operators.lt(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case MUL: v = Operators.mul(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case NE: v = Operators.neq(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case OR: v = Operators.or(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case REM: v = Operators.rem(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case SEQ: v = Operators.stricteq(arg1, arg2, c); break; case SHL: v = Operators.shl(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case SHR: v = Operators.shr(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case SNE: v = Operators.strictneq(arg1, arg2, c); break; case SUB: v = Operators.sub(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case USHR: v = Operators.ushr(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; case XOR: v = Operators.xor(arg1, n.getArg1Register(), arg2, n.getArg2Register(), c); break; default: throw new AnalysisException(); } if (v.isNotPresent() && !Options.get().isPropagateDeadFlow()) { state.setToNone(); return; } if (n.getResultRegister() != AbstractNode.NO_VALUE) state.writeRegister(n.getResultRegister(), v); }