Inheritance: JSIdentifier
示例#1
0
        public bool IsCacheable (JSMethod method) {
            if (method.Reference == null)
                return false;

            var type = method.Reference.DeclaringType;

            // Same-type calls are excluded
            if (TypeUtil.TypesAreEqual(type, ThisType))
                return false;

            // Exclude any type that isn't in our bases or interfaces
            if (!TypeUtil.TypesAreAssignable(TypeInfo, type, ThisType))
                return false;

            // TODO: Exclude interfaces?

            // Exclude generics
            if (TypeUtil.ContainsGenericParameter(type))
                return false;

            if (TypeUtil.IsOpenType(type))
                return false;

            return true;
        }
示例#2
0
        public FunctionAnalysis2ndPass GetSecondPass(JSMethod method)
        {
            var id = method.QualifiedIdentifier;

            Entry entry;
            if (!Cache.TryGetValue(id, out entry)) {
                entry = new Entry {
                    Info = method.Method,
                    Reference = method.Reference,
                    Identifier = id,
                    ParameterNames = new HashSet<string>(from p in method.Method.Parameters select p.Name),
                    SecondPass = new FunctionAnalysis2ndPass(this, method.Method)
                };
                Cache.Add(id, entry);
                OptimizationQueue.Add(id);

                return entry.SecondPass;
            }

            if (entry.SecondPass == null) {
                if (entry.InProgress)
                    return null;

                if (entry.Expression == null)
                    return null;
                else
                    entry.SecondPass = new FunctionAnalysis2ndPass(this, GetFirstPass(id));
            }

            return entry.SecondPass;
        }
示例#3
0
 public JSVerbatimLiteral(JSMethod originalMethod, string expression, IDictionary <string, JSExpression> variables, TypeReference type = null)
     : base(GetValues(variables))
 {
     OriginalMethod = originalMethod;
     Type           = type;
     Expression     = expression;
     Variables      = variables;
 }
示例#4
0
        public void VisitNode (JSMethod method) {
            var cm = GetCachedMethod(method);

            if (cm != null) {
                ParentNode.ReplaceChild(method, cm);
                VisitReplacement(cm);
            } else {
                VisitChildren(method);
            }
        }
示例#5
0
        private JSCachedMethod GetCachedMethod (JSMethod method) {
            if (!IsCacheable(method))
                return null;

            var type = method.Reference.DeclaringType.Resolve();
            if (type == null)
                return null;

            var identifier = new QualifiedMemberIdentifier(
                new TypeIdentifier(type),
                new MemberIdentifier(TypeInfo, method.Reference)
            );

            CachedMethodRecord record;
            if (!CachedMethods.TryGetValue(identifier, out record))
                CachedMethods.Add(identifier, record = new CachedMethodRecord(method, NextID++));

            return new JSCachedMethod(
                method.Reference, method.Method,
                method.MethodTypes, method.GenericArguments,
                record.Index
            );
        }
 protected FunctionAnalysis2ndPass GetSecondPass(JSMethod method)
 {
     return FunctionSource.GetSecondPass(method, Member);
 }
示例#7
0
        protected JSExpression Translate_PropertyCall(JSExpression thisExpression, JSMethod method, JSExpression[] arguments, bool @virtual, bool @static)
        {
            var propertyInfo = method.Method.DeclaringProperty;
            if (propertyInfo == null)
                return null;

            if (propertyInfo.IsIgnored)
                return new JSIgnoredMemberReference(true, propertyInfo, arguments);

            // JS provides no way to override [], so keep it as a regular method call
            if (propertyInfo.Member.IsIndexer())
                return null;

            var parms = method.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSReplacement") ??
                propertyInfo.Metadata.GetAttributeParameters("JSIL.Meta.JSReplacement");
            if (parms != null) {
                var argsDict = new Dictionary<string, JSExpression>();
                argsDict["this"] = thisExpression;
                argsDict["typeof(this)"] = new JSType(thisExpression.GetExpectedType(TypeSystem));

                foreach (var kvp in method.Method.Parameters.Zip(arguments, (p, v) => new { p.Name, Value = v })) {
                    argsDict.Add(kvp.Name, kvp.Value);
                }

                return new JSVerbatimLiteral(method, (string)parms[0].Value, argsDict, propertyInfo.ReturnType);
            }

            var thisType = GetTypeDefinition(thisExpression.GetExpectedType(TypeSystem));
            Func<JSExpression> generate = () => {
                var actualThis = @static ? new JSType(method.Method.DeclaringType.Definition) : thisExpression;

                if ((method.Reference.DeclaringType is GenericInstanceType) && !method.Reference.HasThis) {
                    actualThis = new JSType(method.Reference.DeclaringType);
                }

                if ((propertyInfo.Member.GetMethod != null) && (method.Method.Member.Name == propertyInfo.Member.GetMethod.Name)) {
                    return new JSPropertyAccess(
                        actualThis, new JSProperty(method.Reference, propertyInfo)
                    );
                } else {
                    if (arguments.Length == 0)
                        throw new InvalidOperationException("Attempting to invoke a property setter with no arguments");

                    return new JSBinaryOperatorExpression(
                        JSOperator.Assignment,
                        new JSPropertyAccess(
                            actualThis, new JSProperty(method.Reference, propertyInfo)
                        ),
                        arguments[0], propertyInfo.ReturnType
                    );
                }
            };

            // Accesses to a base property should go through a regular method invocation, since
            //  javascript properties do not have a mechanism for base access
            if (method.Method.Member.HasThis) {
                if (!TypesAreEqual(method.Method.DeclaringType.Definition, thisType) && !@virtual) {
                    return null;
                } else {
                    return generate();
                }
            }

            return generate();
        }
示例#8
0
        protected JSExpression Translate_MethodReplacement(
            JSMethod method, JSExpression thisExpression, 
            JSExpression[] arguments, bool @virtual, bool @static, bool explicitThis
        )
        {
            var methodInfo = method.Method;
            var metadata = methodInfo.Metadata;

            if (metadata != null) {
                var parms = metadata.GetAttributeParameters("JSIL.Meta.JSReplacement");
                if (parms != null) {
                    var argsDict = new Dictionary<string, JSExpression>();
                    argsDict["this"] = thisExpression;
                    argsDict["typeof(this)"] = new JSType(thisExpression.GetExpectedType(TypeSystem));

                    foreach (var kvp in methodInfo.Parameters.Zip(arguments, (p, v) => new { p.Name, Value = v })) {
                        argsDict.Add(kvp.Name, kvp.Value);
                    }

                    return new JSVerbatimLiteral(
                        method, (string)parms[0].Value, argsDict, method.Method.ReturnType
                    );
                }
            }

            if (methodInfo.IsIgnored)
                return new JSIgnoredMemberReference(true, methodInfo, new[] { thisExpression }.Concat(arguments).ToArray());

            switch (method.Method.Member.FullName) {
                case "System.Object JSIL.Builtins::Eval(System.String)":
                    return JSInvocationExpression.InvokeStatic(
                        JS.eval, arguments
                    );
                case "System.Object JSIL.Verbatim::Expression(System.String)": {
                    var expression = arguments[0] as JSStringLiteral;
                    if (expression == null)
                        throw new InvalidOperationException("JSIL.Verbatim.Expression must recieve a string literal as an argument");

                    return new JSVerbatimLiteral(
                        method, expression.Value, null, null
                    );
                }
                case "System.Object JSIL.JSGlobal::get_Item(System.String)": {
                    var expression = arguments[0] as JSStringLiteral;
                    if (expression != null)
                        return new JSDotExpression(
                            JSIL.GlobalNamespace, new JSStringIdentifier(expression.Value, TypeSystem.Object)
                        );
                    else
                        return new JSIndexerExpression(
                            JSIL.GlobalNamespace, arguments[0], TypeSystem.Object
                        );
                }
                case "System.Object JSIL.JSLocal::get_Item(System.String)": {
                    var expression = arguments[0] as JSStringLiteral;
                    if (expression == null)
                        throw new InvalidOperationException("JSLocal must recieve a string literal as an index");

                    return new JSStringIdentifier(expression.Value, TypeSystem.Object);
                }
                case "System.Object JSIL.Builtins::get_This()":
                    return new JSIndirectVariable(Variables, "this", ThisMethodReference);
            }

            JSExpression result = Translate_PropertyCall(thisExpression, method, arguments, @virtual, @static);
            if (result == null) {
                if (@static)
                    result = JSInvocationExpression.InvokeStatic(method.Reference.DeclaringType, method, arguments);
                else if (explicitThis)
                    result = JSInvocationExpression.InvokeBaseMethod(method.Reference.DeclaringType, method, thisExpression, arguments);
                else
                    result = JSInvocationExpression.InvokeMethod(method.Reference.DeclaringType, method, thisExpression, arguments);
            }

            return result;
        }
        private JSExpression ConstructInvocation (
            JSPropertyAccess pa, JSExpression argument = null
        ) {
            JSExpression[] arguments;

            if (argument == null)
                arguments = new JSExpression[0];
            else
                arguments = new JSExpression[] { argument };

            var originalMethod = pa.OriginalMethod;
            var declaringType = originalMethod.Reference.DeclaringType;
            var declaringTypeDef = TypeUtil.GetTypeDefinition(originalMethod.Reference.DeclaringType);
            var thisReferenceType = pa.ThisReference.GetActualType(TypeSystem);
            var isSelf = TypeUtil.TypesAreAssignable(
                TypeInfo, thisReferenceType, declaringType
            );

            // ILSpy converts compound assignments from:
            //  x.set_Value(x.get_Value + n)
            // to
            //  x.get_Value += n;
            // so we have to detect this and reconstruct the correct method
            //  references.
            var actualMethod = originalMethod;
            var correctName = String.Format(
                "{0}_{1}", pa.IsWrite ? "set" : "get",
                pa.Property.Property.ShortName
            );

            if (!actualMethod.Reference.Name.Contains(correctName)) {
                var dt = originalMethod.Method.DeclaringType;

                var actualMethodInfo = dt.Members.Values
                    .OfType<MethodInfo>().FirstOrDefault(
                        (m) => (
                            m.Name.Contains(correctName) &&
                            m.DeclaringType == originalMethod.Method.DeclaringType
                        )
                    );

                MethodReference actualMethodReference = actualMethodInfo.Member;
                if (originalMethod.Reference is GenericInstanceMethod) {
                    throw new InvalidDataException("Reconstructing an invocation of a generic instance method? Shouldn't be possible.");
                } else if (declaringType is GenericInstanceType) {
                    var declaringGit = (GenericInstanceType)declaringType;
                    var returnType = actualMethodReference.ReturnType;

                    if (TypeUtil.IsOpenType(returnType)) {
                        var actualReturnType = JSExpression.SubstituteTypeArgs(TypeInfo, actualMethodReference.ReturnType, actualMethodReference);
                        returnType = actualReturnType;
                    }

                    actualMethodReference = new MethodReference(
                        actualMethodReference.Name, returnType, declaringGit
                    );
                }

                actualMethod = new JSMethod(
                    actualMethodReference, actualMethodInfo,
                    originalMethod.MethodTypes, originalMethod.GenericArguments
                );
            }

            bool needsExplicitThis = !pa.IsVirtualCall && ILBlockTranslator.NeedsExplicitThis(
                declaringType, declaringTypeDef,
                originalMethod.Method.DeclaringType,
                isSelf, thisReferenceType,
                originalMethod.Method
            );
                
            JSInvocationExpressionBase invocation;
            if (pa.Property.Property.IsStatic)
                invocation = JSInvocationExpression.InvokeStatic(
                    actualMethod.Reference.DeclaringType,
                    actualMethod, 
                    arguments
                );
            else if (needsExplicitThis)
                invocation = JSInvocationExpression.InvokeBaseMethod(
                    actualMethod.Reference.DeclaringType,
                    actualMethod, pa.ThisReference,
                    arguments
                );
            else
                invocation = JSInvocationExpression.InvokeMethod(
                    pa.OriginalType, actualMethod, pa.ThisReference, arguments
                );

            JSExpression replacement;
            if (TypeUtil.IsStruct(pa.Property.Property.ReturnType))
                replacement = new JSResultReferenceExpression(invocation);
            else
                replacement = invocation;

            return replacement;
        }
示例#10
0
 public CachedMethodRecord (JSMethod method, int index) {
     Method = method;
     Index = index;
 }
示例#11
0
        public FunctionAnalysis2ndPass GetSecondPass (JSMethod method, QualifiedMemberIdentifier forCaller) {
            if (method == null)
                return null;

            var id = method.QualifiedIdentifier;
            Entry entry = Cache.GetOrCreate(
                id, method, MakeCacheEntry
            );

            if (entry == null)
                return null;

            GetFirstPass(id, forCaller);

            if (!TryAcquireStaticAnalysisDataLock(entry, method.QualifiedIdentifier))
                return null;

            try {
                return _GetOrCreateSecondPass(entry);
            } finally {
                entry.StaticAnalysisDataLock.Exit();
            }
        }
示例#12
0
        public FunctionAnalysis2ndPass GetSecondPass(JSMethod method)
        {
            var id = method.QualifiedIdentifier;

            Entry entry = Cache.GetOrCreate(
                id, method, MakeCacheEntry
            );

            if (entry.SecondPass == null) {
                if (entry.InProgress)
                    return null;

                if (entry.Expression == null)
                    return null;
                else {
                    var firstPass = GetFirstPass(id);
                    try {
                        entry.InProgress = true;
                        entry.SecondPass = new FunctionAnalysis2ndPass(this, firstPass);
                    } finally {
                        entry.InProgress = false;
                    }
                }
            }

            return entry.SecondPass;
        }
示例#13
0
        private void EmitCctors()
        {
            // HACK
            var identifier = (MemberIdentifier)Activator.CreateInstance(
                typeof(MemberIdentifier),
                System.Reflection.BindingFlags.Instance |
                    System.Reflection.BindingFlags.NonPublic,
                null,
                new object[] {
                    true, MemberIdentifier.MemberType.Method,
                    ".cctor", EntryPointAstEmitter.TypeSystem.Void,
                    null, 0
                },
                null
            );

            // Find types we emitted that have static constructors
            var cctors = (
                from t in TypesToStaticInitialize
                let ti = Translator.TypeInfoProvider.GetExisting(t)
                where ti.Members.ContainsKey(identifier)
                let mi = ti.Members[identifier]
                select (MethodInfo)mi
            ).ToList();

            if (cctors.Count == 0)
                return;

            NeedStaticInit = true;
            Formatter.NewLine();

            Formatter.WriteRaw(";; Compiler-generated static constructor dispatcher");
            Formatter.NewLine();
            // If we found any, we need to generate a special function that invokes all the cctors
            Formatter.WriteRaw("(func $__static_init (block ");
            Formatter.Indent();
            Formatter.NewLine();

            // FIXME: Walk cctor dependencies and invoke in correct order
            foreach (var cctor in cctors) {
                // Synthesize a regular static method call
                var jsm = new JSMethod(
                    cctor.Member, cctor, Translator.FunctionCache.MethodTypes
                );
                var call = JSInvocationExpression.InvokeStatic(jsm, new JSExpression[0], false);

                // HACK
                EntryPointAstEmitter.Emit(call);
                Formatter.ConditionalNewLine();
            }

            Formatter.Unindent();
            Formatter.ConditionalNewLine();
            Formatter.WriteRaw(") )");
            Formatter.NewLine();
            Formatter.NewLine();

            Formatter.WriteRaw("(export \"__static_init\" $__static_init)");
            Formatter.NewLine();
        }
示例#14
0
 public JSInvocationExpression NewDelegate (TypeReference delegateType, JSExpression thisReference, JSExpression targetMethod, JSMethod method) {
     return JSInvocationExpression.InvokeStatic(
         new JSDotExpression(
             new JSType(delegateType),
             new JSFakeMethod("New", delegateType, new[] { TypeSystem.Object, TypeSystem.Object }, MethodTypes)
         ), 
         method == null ? new [] { thisReference, targetMethod } : new [] {
             thisReference, 
             targetMethod, 
             new JSDefferedExpression(new JSMethodOfExpression(method.Reference, method.Method, method.MethodTypes, method.GenericArguments)),  },
         true
     );
 }
示例#15
0
 protected FunctionAnalysis2ndPass GetSecondPass(JSMethod method)
 {
     return(FunctionSource.GetSecondPass(method, Member));
 }
示例#16
0
        public FunctionAnalysis2ndPass GetSecondPass(JSMethod method)
        {
            var id = method.QualifiedIdentifier;

            Entry entry = Cache.GetOrCreate(
                id, () => {
                    OptimizationQueue.TryEnqueue(id);

                    return new Entry {
                        Info = method.Method,
                        Reference = method.Reference,
                        Identifier = id,
                        ParameterNames = new HashSet<string>(from p in method.Method.Parameters select p.Name),
                        SecondPass = new FunctionAnalysis2ndPass(this, method.Method)
                    };
                }
            );

            if (entry.SecondPass == null) {
                if (entry.InProgress)
                    return null;

                if (entry.Expression == null)
                    return null;
                else {
                    var firstPass = GetFirstPass(id);
                    try {
                        entry.InProgress = true;
                        entry.SecondPass = new FunctionAnalysis2ndPass(this, firstPass);
                    } finally {
                        entry.InProgress = false;
                    }
                }
            }

            return entry.SecondPass;
        }