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); }
protected bool IsCopyNeeded(JSExpression value, out GenericParameter relevantParameter) { relevantParameter = null; if ((value == null) || (value.IsNull)) { return(false); } while (value is JSReferenceExpression) { value = ((JSReferenceExpression)value).Referent; } 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 (IsTypeExcludedFromCopies(valueType)) { return(false); } var iae = value as JSInitializerApplicationExpression; if ( (value is JSLiteral) || (value is JSNewExpression) || (value is JSPassByReferenceExpression) || (value is JSNewBoxedVariable) || (value is JSDefaultValueLiteral) || (value is JSFieldOfExpression) || ((iae != null) && ((iae.Target is JSNewExpression) || (iae.Target is JSDefaultValueLiteral))) ) { return(false); } if (!OptimizeCopies) { return(true); } if (IsImmutable(value)) { 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) { 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 (Tracing) { Console.WriteLine(String.Format("Returning false from IsCopyNeeded for parameter {0} because reference count is 1 and it has no aliases", value)); } return(false); } } var rightInvocation = value as JSInvocationExpression; if (rightInvocation == null) { return(true); } var invokeMethod = rightInvocation.JSMethod; if (invokeMethod == null) { return(true); } var secondPass = GetSecondPass(invokeMethod); if (secondPass == null) { return(true); } // If this expression is the return value of a function invocation, we can eliminate struct // copies if the return value is a 'new' expression. if (secondPass.ResultIsNew) { return(false); } // We can also eliminate a return value copy if the return value is one of the function's // arguments, and we are sure that argument does not need a copy either. if (secondPass.ResultVariable != null) { var parameters = invokeMethod.Method.Parameters; int parameterIndex = -1; for (var i = 0; i < parameters.Length; i++) { if (parameters[i].Name != secondPass.ResultVariable) { continue; } parameterIndex = i; break; } if (parameterIndex < 0) { return(true); } return(IsCopyNeeded(rightInvocation.Arguments[parameterIndex], out relevantParameter)); } return(true); }