/// <summary>
        /// Try to get a field with given reference in this type.
        /// The declaring type of the method reference is assumed to refer to this type.
        /// </summary>
        public bool TryGet(XFieldReference fieldRef, out XFieldDefinition field)
        {
            // Look in my own fields
            field = Fields.FirstOrDefault(x => x.IsSameExceptDeclaringType(fieldRef));
            if (field != null)
            {
                return(true);
            }

            // Look in base type
            XTypeDefinition baseTypeDef;

            if ((BaseType != null) && BaseType.TryResolve(out baseTypeDef))
            {
                return(baseTypeDef.TryGet(fieldRef, out field));
            }
            return(false);
        }
Exemple #2
0
        /// <summary>
        /// Try to get a field with given reference in this type.
        /// The declaring type of the method reference is assumed to refer to this type.
        /// </summary>
        public bool TryGet(XFieldReference fieldRef, out XFieldDefinition field)
        {
            // Look in my own fields
            field = Fields.FirstOrDefault(x => x.IsSameExceptDeclaringType(fieldRef));
            if (field != null)
                return true;

            // Look in base type
            XTypeDefinition baseTypeDef;
            if ((BaseType != null) && BaseType.TryResolve(out baseTypeDef))
            {
                return baseTypeDef.TryGet(fieldRef, out field);
            }
            return false;
        }
        private static bool InterlockedUsingUpdater(AstExpression interlockedCall, string methodName, XFieldReference field,
                                                    XFieldDefinition updater, AstExpression targetExpr, AstExpression parentExpr,
                                                    AssemblyCompiler compiler)
        {

            bool isStatic = field.Resolve().IsStatic;

            string replacementMethod = null;
            if (methodName == "Increment")
                replacementMethod = "IncrementAndGet";
            else if (methodName == "Decrement")
                replacementMethod = "DecrementAndGet";
            else if (methodName == "Add")
                replacementMethod = "AddAndGet";
            else if (methodName == "Read")
                replacementMethod = "Get";
            else if (methodName.StartsWith("Exchange"))
                replacementMethod = "GetAndSet";
            else if (methodName.StartsWith("CompareAndSet"))
                // this patches through to the original java method for performance purists.
                replacementMethod = "CompareAndSet"; 
            else if (methodName.StartsWith("CompareExchange"))
            {
                if (TransformCompareExchangeToCompareAndSet(parentExpr, compiler, ref interlockedCall))
                    replacementMethod = "CompareAndSet";
                else
                {
                    // The semantics here are slighlty different. Java returns a 'true' on 
                    // success, while BCL returns the old value. We have crafted a replacement 
                    // method with the BCL semantics though.
                    replacementMethod = "CompareExchange";
                }
            }
            else
            {
                return false;
            }

            var updaterType = updater.FieldType.Resolve();
            var methodRef = updaterType.Methods.FirstOrDefault(f => f.Name == replacementMethod);

            if (methodRef == null && methodName=="CompareExchange") 
                methodRef = updaterType.Methods.FirstOrDefault(f => f.Name.StartsWith(replacementMethod));

            if (methodRef == null)
                return false;

            interlockedCall.Operand = methodRef;

            if (isStatic)
                interlockedCall.Arguments[0] = new AstExpression(interlockedCall.SourceLocation, AstCode.Ldnull, null)
                                                    .SetType(field.DeclaringType);
            else
                interlockedCall.Arguments[0] = targetExpr.Arguments[0];

            // add field updater instance argument.
            var ldUpdater = new AstExpression(interlockedCall.SourceLocation, AstCode.Ldsfld, updater)
                                    .SetType(updaterType);

            interlockedCall.Arguments.Insert(0, ldUpdater);

            return true;

        }
Exemple #4
0
 public static XTypeReference GetFieldType(XFieldReference fieldReference)
 {
     return SubstituteTypeArgs(UnpackModifiers(fieldReference.FieldType), fieldReference);
 }
        private static void FailsafeInterlockedUsingLocking(XFieldReference field, AstExpression expr, 
                                                            AstExpression targetExpr, AstBlock block, int idx, 
                                                            AssemblyCompiler compiler, MethodSource currentMethod)
        {
            if (currentMethod.IsDotNet && !currentMethod.ILMethod.DeclaringType.HasSuppressMessageAttribute("InterlockedFallback"))
            {
                bool isStatic = field != null && field.Resolve().IsStatic;

                DLog.Warning(DContext.CompilerCodeGenerator,
                    "Emulating Interlocked call using failsafe locking mechanism in {0}{1}. Consider using AtomicXXX classes instead. You can suppress this message with an [SuppressMessage(\"dot42\", \"InterlockedFallback\")] attribute on the class.",
                    currentMethod.Method.FullName, !isStatic ? "" : " because a static field is referenced");
            }

            // replace with:
            //    Monitor.Enter();
            //    try { <original expression> } finally { Monitor.Exit(); } 
            //   
            // note that the lock is larger than it has to be, since it also sourrounds
            // the parameter evaluation.
            // It must sourround the storing and loading of the reference parameters though.
            var typeSystem = compiler.Module.TypeSystem;

            var monitorType = compiler.GetDot42InternalType("System.Threading", "Monitor");
            var enterMethod = monitorType.Resolve().Methods.Single(p => p.Name == "Enter");
            var exitMethod = monitorType.Resolve().Methods.Single(p => p.Name == "Exit");

            AstExpression loadLockTarget = null;
            
            if (field != null)
            {
                if (field.Resolve().IsStatic)
                {
                    // lock on the field's class typedef.
                    // but always the element type, not on a generic instance (until Dot42 implements proper generic static field handling)
                    loadLockTarget = new AstExpression(expr.SourceLocation, AstCode.LdClass, field.DeclaringType.GetElementType())
                        .SetType(typeSystem.Type);
                }
                else
                {
                    // lock on the fields object
                    loadLockTarget = targetExpr.Arguments[0];
                }
            }

            if (loadLockTarget == null)
            {
                // something went wrong. use a global lock.
                DLog.Warning(DContext.CompilerCodeGenerator, "unable to infer target of Interlocked call. using global lock.");
                var interlockedType = compiler.GetDot42InternalType("System.Threading", "Interlocked");
                loadLockTarget = new AstExpression(expr.SourceLocation, AstCode.LdClass, interlockedType)
                                        .SetType(typeSystem.Type);
            }

            var lockVar = new AstGeneratedVariable("lockTarget$", "") {Type = typeSystem.Object};
            var storeLockVar = new AstExpression(expr.SourceLocation, AstCode.Stloc, lockVar, loadLockTarget);
            var loadLockVar = new AstExpression(expr.SourceLocation, AstCode.Ldloc, lockVar);
            var enterCall = new AstExpression(expr.SourceLocation, AstCode.Call, enterMethod, storeLockVar);

            var replacementBlock = new AstBlock(expr.SourceLocation);
            replacementBlock.Body.Add(enterCall);

            var tryCatch = new AstTryCatchBlock(expr.SourceLocation)
            {
                TryBlock = new AstBlock(expr.SourceLocation, expr),
                FinallyBlock = new AstBlock(expr.SourceLocation,
                    new AstExpression(block.SourceLocation, AstCode.Call, exitMethod, loadLockVar))
            };

            replacementBlock.Body.Add(tryCatch);

            if (block.EntryGoto == expr)
                block.EntryGoto = enterCall;

            block.Body[idx] = replacementBlock;
        }
Exemple #6
0
 /// <summary>
 /// Is this reference equal to the given other reference?
 /// </summary>
 public virtual bool IsSameExceptDeclaringType(XFieldReference other)
 {
     return (Name == other.Name) && FieldType.IsSame(other.FieldType);
 }
Exemple #7
0
 /// <summary>
 /// Is this reference equal to the given other reference?
 /// </summary>
 public bool IsSame(XFieldReference other)
 {
     return DeclaringType.IsSame(other.DeclaringType) && IsSameExceptDeclaringType(other);
 }
Exemple #8
0
 /// <summary>
 /// Is this reference equal to the given other reference?
 /// </summary>
 public virtual bool IsSameExceptDeclaringType(XFieldReference other)
 {
     return((Name == other.Name) && FieldType.IsSame(other.FieldType));
 }
Exemple #9
0
 /// <summary>
 /// Is this reference equal to the given other reference?
 /// </summary>
 public bool IsSame(XFieldReference other)
 {
     return(DeclaringType.IsSame(other.DeclaringType) && IsSameExceptDeclaringType(other));
 }