protected JSVariable GetConstructedReference(JSPassByReferenceExpression pbr) { JSVariable referentVariable; JSExpression referent; if (!JSReferenceExpression.TryMaterialize(JSIL, pbr.Referent, out referent)) { // If the reference can be dereferenced, but cannot be materialized, it is // a constructed reference. if (JSReferenceExpression.TryDereference(JSIL, pbr.Referent, out referent)) { referentVariable = referent as JSVariable; // Ignore variables we previously transformed. if ((referentVariable != null) && TransformedVariables.Contains(referentVariable.Identifier)) { return(null); } return(referentVariable); } else { return(null); } } referentVariable = referent as JSVariable; if (referentVariable == null) { return(null); } // Ignore variables we previously transformed. if (TransformedVariables.Contains(referentVariable.Identifier)) { return(null); } // If the variable does not match the one in the dictionary, it is a constructed // reference to a parameter. if (!referentVariable.Equals(Variables[referentVariable.Identifier])) { // If the parameter is a reference, we don't care about it. if (Variables[referentVariable.Identifier].IsReference) { return(null); } else { return(referentVariable); } } return(null); }
public void VisitNode(JSReferenceExpression re) { if (re.Referent.IsConstant) { Visit(re.Referent); } else { Console.WriteLine("Can't translate {0}", re); Formatter.WriteSExpr("untranslatable.reference"); } }
public void VisitNode(JSBinaryOperatorExpression boe) { JSExpression left; if (!JSReferenceExpression.TryDereference(JSIL, boe.Left, out left)) { left = boe.Left; } var leftVar = left as JSVariable; var leftChangeType = left as JSChangeTypeExpression; if (leftChangeType != null) { leftVar = leftChangeType.Expression as JSVariable; } if ( !(ParentNode is JSVariableDeclarationStatement) && (leftVar != null) && (leftVar.Identifier == Variable.Identifier) ) { if (boe.Operator is JSAssignmentOperator) { var replacement = new JSWriteThroughReferenceExpression( Variable, boe.Right ); ParentNode.ReplaceChild(boe, replacement); VisitReplacement(replacement); } else { VisitChildren(boe); } } else if (ParentNode is JSVariableDeclarationStatement) { // Don't walk through the left-hand side of variable declarations. VisitChildren( boe, (node, name) => name != "Left" ); } else { VisitChildren(boe); } }
protected bool IsCopyAlwaysUnnecessaryForAssignmentTarget(JSExpression target) { target = JSReferenceExpression.Strip(target); var targetDot = target as JSDotExpressionBase; // The assignment is performing a write into an element proxy, so a copy is unnecessary // because the element proxy immediately unpacks the value into the array. if ((targetDot != null) && PackedArrayUtil.IsElementProxy(targetDot.Target)) { return(true); } return(false); }
public void VisitNode(JSPassByReferenceExpression byref) { JSExpression referent; if (JSReferenceExpression.TryMaterialize(JSIL, byref.Referent, out referent)) { Output.Comment("ref"); Visit(referent); } else { Output.Identifier("JSIL.UnmaterializedReference", null); Output.LPar(); Output.RPar(); } }
public void VisitNode(JSUnaryOperatorExpression uoe) { JSExpression expr; if (!JSReferenceExpression.TryDereference(JSIL, uoe.Expression, out expr)) { expr = uoe.Expression; } var eVar = expr as JSVariable; var eChangeType = expr as JSChangeTypeExpression; if (eChangeType != null) { eVar = eChangeType.Expression as JSVariable; } var type = uoe.Expression.GetActualType(TypeSystem); if ( (eVar != null) && (eVar.Identifier == Variable.Identifier) && (uoe.Operator is JSUnaryMutationOperator) ) { var newValue = DecomposeMutationOperators.DecomposeUnaryMutation( uoe, () => TemporaryVariable.ForFunction( Stack.Last() as JSFunctionExpression, type ), type, TypeSystem ); var replacement = new JSWriteThroughReferenceExpression( Variable, newValue ); ParentNode.ReplaceChild(uoe, replacement); VisitReplacement(replacement); } else { VisitChildren(uoe); } }
protected JSVariable GetReferentVariable(JSPassByReferenceExpression pbr) { JSVariable referentVariable; JSExpression referent; if (!JSReferenceExpression.TryMaterialize(JSIL, pbr.Referent, out referent)) { if (JSReferenceExpression.TryDereference(JSIL, pbr.Referent, out referent)) { referentVariable = referent as JSVariable; return(referentVariable); } else { return(null); } } referentVariable = referent as JSVariable; return(referentVariable); }
public void VisitNode(JSNewBoxedVariable nbv) { GenericParameter relevantParameter; var initialValue = nbv.InitialValue; var initialValueDerefed = initialValue; initialValueDerefed = JSReferenceExpression.Strip(initialValueDerefed); var initialValueType = initialValueDerefed.GetActualType(TypeSystem); if (!nbv.SuppressClone && IsCopyNeeded(nbv.InitialValue, out relevantParameter) && // We don't need to make a copy if the source value is a reference (like T& this) !((initialValueType) != null && initialValueType.IsByReference) ) { nbv.ReplaceChild(nbv.InitialValue, new JSStructCopyExpression(nbv.InitialValue)); } VisitChildren(nbv); }
protected bool IsCopyNeededForAssignmentTarget(JSExpression target) { target = JSReferenceExpression.Strip(target); if (!OptimizeCopies) { return(true); } if (IsImmutable(target)) { return(false); } var variable = target as JSVariable; if (variable != null) { return(SecondPass.IsVariableModified(variable.Name)); } return(true); }
protected bool IsImmutable(JSExpression target) { target = JSReferenceExpression.Strip(target); var fieldAccess = target as JSFieldAccess; if (fieldAccess != null) { return(fieldAccess.Field.Field.Metadata.HasAttribute("JSIL.Meta.JSImmutable")); } var dot = target as JSDotExpressionBase; if (dot != null) { if (IsImmutable(dot.Target)) { return(true); } else if (IsImmutable(dot.Member)) { return(true); } } var indexer = target as JSIndexerExpression; if (indexer != null) { if (IsImmutable(indexer.Target)) { return(true); } } return(false); }
protected bool IsCopyNeeded( JSExpression value, out GenericParameter relevantParameter, bool allowImmutabilityOptimizations = true ) { relevantParameter = null; if ((value == null) || (value.IsNull)) { return(false); } value = JSReferenceExpression.Strip(value); var sce = value as JSStructCopyExpression; if (sce != null) { return(false); } var valueType = value.GetActualType(TypeSystem); var valueTypeDerefed = TypeUtil.DereferenceType(valueType) ?? valueType; var cte = value as JSChangeTypeExpression; var cast = value as JSCastExpression; TypeReference originalType; int temp; if (cte != null) { originalType = cte.Expression.GetActualType(TypeSystem); } else if (cast != null) { originalType = cast.Expression.GetActualType(TypeSystem); } else { originalType = null; } if (originalType != null) { originalType = TypeUtil.FullyDereferenceType(originalType, out temp); if (!IsStructOrGenericParameter(valueTypeDerefed) && !IsStructOrGenericParameter(originalType)) { return(false); } relevantParameter = (originalType as GenericParameter) ?? (valueTypeDerefed as GenericParameter); } else { if (!IsStructOrGenericParameter(valueTypeDerefed)) { return(false); } relevantParameter = (valueTypeDerefed as GenericParameter); } if (value is JSValueOfNullableExpression) { return(true); } if (IsTypeExcludedFromCopies(valueType)) { return(false); } if ( (value is JSLiteral) || (value is JSNewExpression) || (value is JSPassByReferenceExpression) || (value is JSNewBoxedVariable) || (value is JSDefaultValueLiteral) || (value is JSFieldOfExpression) ) { return(false); } if (!OptimizeCopies) { return(true); } if (IsImmutable(value) && allowImmutabilityOptimizations) { return(false); } var valueDot = value as JSDotExpressionBase; // The value is being read out of an element proxy, so no copy is necessary - the read unpacks the value // on demand from the packed array. if ( (valueDot != null) && PackedArrayUtil.IsElementProxy(valueDot.Target) ) { // return false; } var valueTypeInfo = TypeInfo.GetExisting(valueType); if ((valueTypeInfo != null) && valueTypeInfo.IsImmutable && allowImmutabilityOptimizations) { return(false); } // If the expression is a parameter that is only used once and isn't aliased, // we don't need to copy it. var rightVar = value as JSVariable; if (rightVar != null) { int referenceCount; if ( ReferenceCounts.TryGetValue(rightVar.Identifier, out referenceCount) && (referenceCount == 1) && !rightVar.IsReference && rightVar.IsParameter && !SecondPass.VariableAliases.ContainsKey(rightVar.Identifier) ) { if (TraceElidedCopies) { Console.WriteLine(String.Format("Returning false from IsCopyNeeded for parameter {0} because reference count is 1 and it has no aliases", value)); } return(false); } } return(true); }
public void VisitNode(JSBinaryOperatorExpression boe) { JSExpression left, right, nestedLeft; if (!JSReferenceExpression.TryDereference(JSIL, boe.Left, out left)) { left = boe.Left; } if (!JSReferenceExpression.TryDereference(JSIL, boe.Right, out right)) { right = boe.Right; } var nestedBoe = right as JSBinaryOperatorExpression; var isAssignment = (boe.Operator == JSOperator.Assignment); var leftNew = left as JSNewExpression; var rightNew = right as JSNewExpression; var leftVar = left as JSVariable; if ( isAssignment && (nestedBoe != null) && (left.IsConstant || (leftVar != null) || left is JSDotExpressionBase) && !(ParentNode is JSVariableDeclarationStatement) ) { JSUnaryOperator prefixOperator; JSAssignmentOperator compoundOperator; if (!JSReferenceExpression.TryDereference(JSIL, nestedBoe.Left, out nestedLeft)) { nestedLeft = nestedBoe.Left; } var rightLiteral = nestedBoe.Right as JSIntegerLiteral; var areEqual = left.Equals(nestedLeft); if ( areEqual && PrefixOperators.TryGetValue(nestedBoe.Operator, out prefixOperator) && (rightLiteral != null) && (rightLiteral.Value == 1) ) { var newUoe = new JSUnaryOperatorExpression( prefixOperator, boe.Left, boe.GetActualType(TypeSystem) ); ParentNode.ReplaceChild(boe, newUoe); VisitReplacement(newUoe); return; } else if ( areEqual && CompoundAssignments.TryGetValue(nestedBoe.Operator, out compoundOperator) ) { var newBoe = new JSBinaryOperatorExpression( compoundOperator, boe.Left, nestedBoe.Right, boe.GetActualType(TypeSystem) ); ParentNode.ReplaceChild(boe, newBoe); VisitReplacement(newBoe); return; } } else if ( isAssignment && (leftNew != null) && (rightNew != null) ) { var rightType = rightNew.Type as JSDotExpressionBase; if ( (rightType != null) && (rightType.Member.Identifier == "CollectionInitializer") ) { var newInitializer = new JSInitializerApplicationExpression( boe.Left, new JSArrayExpression( TypeSystem.Object, rightNew.Arguments.ToArray() ) ); ParentNode.ReplaceChild(boe, newInitializer); VisitReplacement(newInitializer); return; } } else if ( isAssignment && (leftVar != null) && leftVar.IsThis ) { var leftType = leftVar.GetActualType(TypeSystem); if (!TypeUtil.IsStruct(leftType)) { ParentNode.ReplaceChild(boe, new JSUntranslatableExpression(boe)); return; } else { var newInvocation = JSInvocationExpression.InvokeStatic( JSIL.CopyMembers, new[] { boe.Right, leftVar } ); ParentNode.ReplaceChild(boe, newInvocation); VisitReplacement(newInvocation); return; } } VisitChildren(boe); }
public void VisitNode(JSReferenceExpression reference) { Visit(reference.Referent); }