public void VisitNode(JSInvocationExpression invocation) { var jsm = invocation.JSMethod; MethodInfo method = null; if (jsm != null) { method = jsm.Method; } bool isOverloaded = (method != null) && method.IsOverloadedRecursive && !method.Metadata.HasAttribute("JSIL.Meta.JSRuntimeDispatch"); if (isOverloaded && JavascriptAstEmitter.CanUseFastOverloadDispatch(method)) { isOverloaded = false; } if ((method != null) && method.DeclaringType.IsInterface) { // HACK if (!PackedArrayUtil.IsPackedArrayType(jsm.Reference.DeclaringType)) { CacheInterfaceMember(jsm.Reference.DeclaringType, jsm.Identifier); } } if ((jsm != null) && (method != null) && isOverloaded) { CacheSignature(jsm.Reference, method.Signature, false); } VisitChildren(invocation); }
public JSNewArrayElementReference NewElementReference(JSExpression target, JSExpression index) { var arrayType = TypeUtil.DereferenceType(target.GetActualType(TypeSystem)); TypeReference resultType; if (PackedArrayUtil.IsPackedArrayType(arrayType)) { resultType = new ByReferenceType( PackedArrayUtil.GetElementType(arrayType) ); } else if (TypeUtil.IsArray(arrayType)) { resultType = new ByReferenceType( TypeUtil.GetElementType(arrayType, true) ); } else { throw new ArgumentException("Cannot create a reference to an element of a value of type '" + arrayType.FullName + "'", target.ToString()); } if (PackedArrayUtil.IsPackedArrayType(target.GetActualType(TypeSystem))) { return(new JSNewPackedArrayElementReference(resultType, target, index)); } else { return(new JSNewArrayElementReference(resultType, target, index)); } }
public void VisitNode(JSNewArrayExpression nae) { var parentBoe = ParentNode as JSBinaryOperatorExpression; if (parentBoe != null) { var leftField = parentBoe.Left as JSFieldAccess; if ( (leftField != null) && PackedArrayUtil.IsPackedArrayType(leftField.Field.Field.FieldType) ) { JSNewPackedArrayExpression replacement; if (nae.Dimensions != null) { replacement = new JSNewPackedArrayExpression(leftField.Field.Field.FieldType, nae.ElementType, nae.Dimensions, nae.SizeOrArrayInitializer); } else { replacement = new JSNewPackedArrayExpression(leftField.Field.Field.FieldType, nae.ElementType, nae.SizeOrArrayInitializer); } ParentNode.ReplaceChild(nae, replacement); VisitReplacement(replacement); return; } } VisitChildren(nae); }
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); }
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); }