예제 #1
0
        // NOTE: May be called on invalid definitions
        // See also: InlinedMethodCache::PrimIsInlinable
        public bool IsInlinable(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, InstanceState state)
        {
            if (!env.InlinedMethods.CouldBeInlinableBasedOnHeaderAlone(assemblyDef, typeDef, methodDef))
                return false;

            if (methodDef.IsStatic && methodDef.IsConstructor)
                // Static constructors are invoked by type initializers
                return false;

            if (!IsImported(assemblyDef, typeDef, methodDef))
                // Not an imported method
                return false;

            if (!methodDef.IsStatic && methodDef.IsConstructor)
            {
                // Instance constructors need too much surrounding logic to be worth inlining,
                // but constructors for 'Merged' types must be inlined
                return state == InstanceState.Merged;
            }

            var outer = typeDef.OuterPropertyOrEvent(methodDef.MethodSignature);
            if (outer != null && outer.Flavor == CST.MemberDefFlavor.Event)
                // Event adders/removers need too much surrounding logic to be worth inlining
                return false;

            var isInline = default(bool);
            if (env.AttributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 env.AttributeHelper.InlineAttributeRef,
                 env.AttributeHelper.TheIsInlinedProperty,
                 true,
                 false,
                 ref isInline))
                // User has specified whether or not to inline, which overrides size-based determination
                return isInline;

            var script = default(JST.Expression);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ImportAttributeRef,
                 attributeHelper.TheScriptProperty,
                 true,
                 false,
                 ref script);
            // Use script size, even though actual function size may be a bit larger after adjusting for
            // various import flavors
            return script == null || script.Size <= env.ImportInlineThreshold;
        }
예제 #2
0
        // NOTE: May be called on invalid definitions
        public bool IsImported(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef)
        {
            var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef);

            var outerDef = typeDef.OuterPropertyOrEvent(methodDef.MethodSignature);
            if (outerDef != null)
            {
                switch (outerDef.Flavor)
                {
                case CST.MemberDefFlavor.Event:
                    {
                        var eventDef = (CST.EventDef)outerDef;
                        if (eventDef.Add != null && eventDef.Remove != null)
                        {
                            var n = 0;
                            if (attributeHelper.MethodHasAttribute
                                (assemblyDef,
                                 typeDef,
                                 typeDef.ResolveMethod(eventDef.Add),
                                 attributeHelper.ImportAttributeRef,
                                 false,
                                 false))
                                n++;
                            if (attributeHelper.MethodHasAttribute
                                (assemblyDef,
                                 typeDef,
                                 typeDef.ResolveMethod(eventDef.Remove),
                                 attributeHelper.ImportAttributeRef,
                                 false,
                                 false))
                                n++;
                            if (n == 1)
                            {
                                env.Log
                                    (new InvalidInteropMessage
                                         (ctxt, "events with adders and removers must be imported simultaneously"));
                                throw new DefinitionException();
                            }
                        }
                        break;
                    }
                case CST.MemberDefFlavor.Property:
                    {
                        var propDef = (CST.PropertyDef)outerDef;
                        if (propDef.Get != null && propDef.Set != null)
                        {
                            var n = 0;
                            if (attributeHelper.MethodHasAttribute
                                (assemblyDef,
                                 typeDef,
                                 typeDef.ResolveMethod(propDef.Get),
                                 attributeHelper.ImportAttributeRef,
                                 false,
                                 false))
                                n++;
                            if (attributeHelper.MethodHasAttribute
                                (assemblyDef,
                                 typeDef,
                                 typeDef.ResolveMethod(propDef.Set),
                                 attributeHelper.ImportAttributeRef,
                                 false,
                                 false))
                                n++;
                            if (n == 1)
                            {
                                env.Log
                                    (new InvalidInteropMessage
                                         (ctxt, "properties with getters and setters must be imported simultaneously"));
                                throw new DefinitionException();
                            }
                        }
                        break;
                    }
                case CST.MemberDefFlavor.Field:
                case CST.MemberDefFlavor.Method:
                    throw new InvalidOperationException("not a property or event");
                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            if (IsExtern(assemblyDef, typeDef, methodDef))
            {
                if (attributeHelper.MethodHasAttribute
                    (assemblyDef, typeDef, methodDef, attributeHelper.ImportAttributeRef, true, false))
                {
                    if (attributeHelper.MethodHasAttribute
                        (assemblyDef, typeDef, methodDef, env.Global.DllImportAttributeRef, false, false))
                    {
                        env.Log(new InvalidInteropMessage(ctxt, "cannot mix 'Import' and 'DllImport' attributes"));
                        throw new DefinitionException();
                    }
                    return true;
                }
                else
                    return false;
            }
            else
            {
                if (attributeHelper.MethodHasAttribute
                    (assemblyDef, typeDef, methodDef, attributeHelper.ImportAttributeRef, false, false))
                {
                    if (outerDef == null)
                    {
                        env.Log
                            (new InvalidInteropMessage
                                 (ctxt, "cannot Import a method which already has an implementation"));
                        throw new DefinitionException();
                    }
                    // else: C# doesn't allow extern properties, so be forgiving here
                    return true;
                }
                return false;
            }
        }
예제 #3
0
        private JST.Expression RecasePropertyEvent(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression script)
        {
            var outer = typeDef.OuterPropertyOrEvent(methodDef.MethodSignature);
            if (outer == null)
                throw new ArgumentException("not a getter/setter/adder/remover method");

            if (script != null)
                return script;

            var casing = default(Casing);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.NamingAttributeRef,
                 attributeHelper.TheMemberNameCasingProperty,
                 true,
                 false,
                 ref casing);
            return new JST.Identifier(JST.Lexemes.StringToIdentifier(Recase(outer.Name, casing))).ToE();
        }
예제 #4
0
        public void AppendExport(JST.NameSupply nameSupply, JST.Identifier rootId, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression instance, Seq<JST.Statement> body, AppendCallExported appendCallExported)
        {
            var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef);
            if (methodDef.TypeArity > 0)
            {
                env.Log(new InvalidInteropMessage(ctxt, "polymorphic methods cannot be exported"));
                throw new DefinitionException();
            }
            if (typeDef.Arity > 0 && (methodDef.IsConstructor || methodDef.IsStatic))
            {
                env.Log
                    (new InvalidInteropMessage
                         (ctxt, "higher-kinded types cannot export static methods or instance constructors"));
                throw new DefinitionException();
            }

            CheckParameterAndReturnTypesAreImportableExportable(assemblyDef, typeDef, methodDef);

            var script = default(JST.Expression);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ExportAttributeRef,
                 attributeHelper.TheScriptProperty,
                 true,
                 false,
                 ref script);
            var outer = typeDef.OuterPropertyOrEvent(methodDef.MethodSignature);

            if (!methodDef.IsStatic && methodDef.IsConstructor)
            {
                // Constructors
                if (methodDef.TypeArity > 0)
                    throw new InvalidOperationException("invalid constructor");
            }
            else if (outer != null)
            {
                var localScript = default(JST.Expression);
                var hasLocalScript = attributeHelper.GetValueFromMethod
                    (assemblyDef,
                     typeDef,
                     methodDef,
                     attributeHelper.ExportAttributeRef,
                     attributeHelper.TheScriptProperty,
                     false,
                     false,
                     ref localScript);
                switch (outer.Flavor)
                {
                case CST.MemberDefFlavor.Event:
                    {
                        var eventDef = (CST.EventDef)outer;
                        if (eventDef.Add != null && methodDef.Signature.Equals(eventDef.Add))
                            // Adder
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "add", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "add", script);
                        else if (eventDef.Remove != null && methodDef.Signature.Equals(eventDef.Remove))
                            // Remover
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "remove", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "remove", script);
                        else
                            throw new InvalidOperationException();
                        break;
                    }
                case CST.MemberDefFlavor.Property:
                    {
                        var propDef = (CST.PropertyDef)outer;
                        if (propDef.Get != null && methodDef.Signature.Equals(propDef.Get))
                            // Getter
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "get", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "get", script);
                        else if (propDef.Set != null && methodDef.Signature.Equals(propDef.Set))
                            // Setter
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "set", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "set", script);
                        else
                            throw new InvalidOperationException();
                        break;
                    }
                case CST.MemberDefFlavor.Field:
                case CST.MemberDefFlavor.Method:
                    throw new InvalidOperationException("not a property or event");
                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            else
            {
                // Normal methods
                script = RecaseMethod(assemblyDef, typeDef, methodDef, script);
            }

            script = PrefixName(assemblyDef, typeDef, methodDef, script, true);
            AppendFinalExport
                (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, instance, body, appendCallExported);
        }
예제 #5
0
        public JST.Expression AppendImport(JST.NameSupply nameSupply, JST.Identifier rootId, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, ISeq<JST.Statement> body, IImSeq<JST.Expression> arguments)
        {
            var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef);
            CheckParameterAndReturnTypesAreImportableExportable(assemblyDef, typeDef, methodDef);

            var script = default(JST.Expression);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ImportAttributeRef,
                 attributeHelper.TheScriptProperty,
                 true,
                 false,
                 ref script);

            if (!methodDef.IsStatic && methodDef.IsConstructor)
            {
                // Constructor
                if (script == null)
                {
                    var creation = default(Creation);
                    attributeHelper.GetValueFromMethod
                        (assemblyDef,
                         typeDef,
                         methodDef,
                         attributeHelper.ImportAttributeRef,
                         attributeHelper.TheCreationProperty,
                         true,
                         false,
                         ref creation);
                    switch (creation)
                    {
                    case Creation.Constructor:
                        script = PrefixName(assemblyDef, typeDef, methodDef, null, false);
                        break;
                    case Creation.Object:
                        if (arguments.Count > 0)
                        {
                            env.Log
                                (new InvalidInteropMessage
                                     (ctxt, "imported constructors for object literals cannot have arguments"));
                            throw new DefinitionException();
                        }
                        script = Constants.Object.ToE();
                        break;
                    case Creation.Array:
                        script = Constants.Array.ToE();
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    var call = AppendFinalImport
                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                    return new JST.NewExpression(call);
                }
                else if (script is JST.FunctionExpression)
                    return AppendFinalImport
                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                else
                {
                    script = PrefixName(assemblyDef, typeDef, methodDef, script, false);
                    var call = AppendFinalImport
                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                    return new JST.NewExpression(call);
                }
            }
            else
            {
                var outer = typeDef.OuterPropertyOrEvent(methodDef.MethodSignature);
                if (outer != null)
                {
                    var isOnMethod = attributeHelper.MethodHasAttribute
                        (assemblyDef, typeDef, methodDef, attributeHelper.ImportAttributeRef, false, false);
                    var localScript = default(JST.Expression);
                    if (isOnMethod)
                        attributeHelper.GetValueFromMethod
                            (assemblyDef,
                             typeDef,
                             methodDef,
                             attributeHelper.ImportAttributeRef,
                             attributeHelper.TheScriptProperty,
                             false,
                             false,
                             ref localScript);

                    switch (outer.Flavor)
                    {
                    case CST.MemberDefFlavor.Property:
                        {
                            var propDef = (CST.PropertyDef)outer;
                            if (propDef.Get != null && methodDef.Signature.Equals(propDef.Get))
                            {
                                // Getter
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         GetterSetterAdderRemoverNameFromMethod
                                             (assemblyDef, typeDef, methodDef, "get", localScript),
                                         false);
                                    return AppendFinalImport
                                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log
                                        (new InvalidInteropMessage
                                             (ctxt, "property import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    if (script == null && arguments.Count == 2 && !methodDef.IsStatic)
                                        return new JST.IndexExpression(arguments[0], arguments[1]);
                                    else
                                    {
                                        script = PrefixName
                                            (assemblyDef,
                                             typeDef,
                                             methodDef,
                                             RecasePropertyEvent(assemblyDef, typeDef, methodDef, script),
                                             false);
                                        if (methodDef.IsStatic && arguments.Count == 0)
                                            return script;
                                        else if (!methodDef.IsStatic && arguments.Count == 1)
                                            return JST.Expression.Dot
                                                (arguments[0], JST.Expression.ExplodePath(script));
                                        else
                                        {
                                            env.Log
                                                (new InvalidInteropMessage
                                                     (ctxt,
                                                      "additional getter parameters not supported for default getters"));
                                            throw new DefinitionException();
                                        }
                                    }
                                }
                            }
                            else if (propDef.Set != null && methodDef.Signature.Equals(propDef.Set))
                            {
                                // Setter
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         GetterSetterAdderRemoverNameFromMethod
                                             (assemblyDef, typeDef, methodDef, "set", localScript),
                                         false);
                                    return AppendFinalImport
                                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log
                                        (new InvalidInteropMessage
                                             (ctxt, "property import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    if (script == null && arguments.Count == 3 && !methodDef.IsStatic)
                                        return new JST.BinaryExpression
                                            (new JST.IndexExpression(arguments[0], arguments[1]),
                                             JST.BinaryOp.Assignment,
                                             arguments[2]);
                                    else
                                    {
                                        script = PrefixName
                                            (assemblyDef,
                                             typeDef,
                                             methodDef,
                                             RecasePropertyEvent(assemblyDef, typeDef, methodDef, script),
                                             false);
                                        if (methodDef.IsStatic && arguments.Count == 1)
                                            return new JST.BinaryExpression
                                                (script, JST.BinaryOp.Assignment, arguments[0]);
                                        else if (!methodDef.IsStatic && arguments.Count == 2)
                                            return new JST.BinaryExpression
                                                (JST.Expression.Dot(arguments[0], JST.Expression.ExplodePath(script)),
                                                 JST.BinaryOp.Assignment,
                                                 arguments[1]);
                                        else
                                        {
                                            env.Log
                                                (new InvalidInteropMessage
                                                     (ctxt,
                                                      "additional setter parameters not supported for default setters"));
                                            throw new DefinitionException();
                                        }
                                    }
                                }
                            }
                            else
                                throw new InvalidOperationException();
                        }
                    case CST.MemberDefFlavor.Event:
                        {
                            var eventDef = (CST.EventDef)outer;
                            // XREF1201
                            if (eventDef.Add != null && methodDef.Signature.Equals(eventDef.Add))
                            {
                                // Adder
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         GetterSetterAdderRemoverNameFromMethod
                                             (assemblyDef, typeDef, methodDef, "add", localScript),
                                         false);
                                    return AppendFinalImport
                                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log
                                        (new InvalidInteropMessage(ctxt, "event import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    // The delegate argument has already taken account of the combine, so 
                                    // just a field assignment
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         RecasePropertyEvent(assemblyDef, typeDef, methodDef, script),
                                         false);
                                    if (methodDef.IsStatic && arguments.Count == 1)
                                        return new JST.BinaryExpression(script, JST.BinaryOp.Assignment, arguments[0]);
                                    else if (!methodDef.IsStatic && arguments.Count == 2)
                                        return new JST.BinaryExpression
                                            (JST.Expression.Dot(arguments[0], JST.Expression.ExplodePath(script)),
                                             JST.BinaryOp.Assignment,
                                             arguments[1]);
                                    else
                                        throw new InvalidOperationException("mismatched event adder arity");
                                }
                            }
                            else if (eventDef.Remove != null && methodDef.Signature.Equals(eventDef.Remove))
                            {
                                // Remover
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         GetterSetterAdderRemoverNameFromMethod
                                             (assemblyDef, typeDef, methodDef, "remove", localScript),
                                         false);
                                    return AppendFinalImport
                                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log
                                        (new InvalidInteropMessage(ctxt, "event import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    // The delegate argument has already taken account of the delete, so 
                                    // just a field assignment
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         RecasePropertyEvent(assemblyDef, typeDef, methodDef, script),
                                         false);
                                    if (methodDef.IsStatic && arguments.Count == 1)
                                        return new JST.BinaryExpression(script, JST.BinaryOp.Assignment, arguments[0]);
                                    else if (!methodDef.IsStatic && arguments.Count == 2)
                                        return new JST.BinaryExpression
                                            (JST.Expression.Dot(arguments[0], JST.Expression.ExplodePath(script)),
                                             JST.BinaryOp.Assignment,
                                             arguments[1]);
                                    else
                                        throw new InvalidOperationException("mismatched event remover arity");
                                }
                            }
                            else
                                throw new InvalidOperationException();
                        }
                    case CST.MemberDefFlavor.Field:
                    case CST.MemberDefFlavor.Method:
                        throw new InvalidOperationException("outer is not property or event");
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
                else
                {
                    // Normal method
                    script = PrefixName
                        (assemblyDef, typeDef, methodDef, RecaseMethod(assemblyDef, typeDef, methodDef, script), false);
                    return AppendFinalImport
                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                }
            }
        }