/** 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); }
/** 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); }
/** 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)); }
/** 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()); }
/** 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); }
/** 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); }
/** 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.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); }