Example #1
0
        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);
        }
Example #2
0
        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));
            }
        }
Example #3
0
        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);
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        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);
        }