Ejemplo n.º 1
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
                       ));
        }
Ejemplo n.º 2
0
            public Invocation(
                int[] parentNodeIndices, int statementIndex, int nodeIndex,
                JSVariable thisVariable, JSMethod method, object nonJSMethod,
                IDictionary <string, string[]> variables
                ) : base(parentNodeIndices, statementIndex, nodeIndex)
            {
                if (thisVariable != null)
                {
                    ThisVariable = thisVariable.Identifier;
                }
                else
                {
                    ThisVariable = null;
                }

                ThisType = null;
                Method   = method;
                if (method == null)
                {
                    NonJSMethod = nonJSMethod;
                }
                else
                {
                    NonJSMethod = null;
                }
                Variables = variables;
            }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
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();
            }
        }
Ejemplo n.º 5
0
 public Invocation(int statementIndex, int nodeIndex, JSVariable thisVariable, JSMethod method, IDictionary <string, string[]> variables)
     : base(statementIndex, nodeIndex)
 {
     ThisVariable = thisVariable.Identifier;
     ThisType     = null;
     Method       = method;
     Variables    = variables;
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Writes an interface member reference to the output.
        /// </summary>
        public void WriteInterfaceMemberToOutput(
            JavascriptFormatter output, Compiler.Extensibility.IAstEmitter astEmitter,
            JSFunctionExpression enclosingFunction,
            JSMethod jsMethod, JSExpression method,
            TypeReferenceContext referenceContext
            )
        {
            int index;

            CachedInterfaceMemberRecord record;

            GenericParameter[] rewrittenGenericParameters = null;
            if (LocalCachingEnabled && PreferLocalCacheForGenericInterfaceMethodSignatures)
            {
                record = new CachedInterfaceMemberRecord(jsMethod.Reference.DeclaringType, jsMethod.Identifier);
            }
            else
            {
                var rewritten = GenericTypesRewriter.Normalized(jsMethod.Reference.DeclaringType);
                record = new CachedInterfaceMemberRecord(rewritten.CacheRecord, jsMethod.Identifier,
                                                         rewritten.RewritedGenericParameters.Length);
                rewrittenGenericParameters = rewritten.RewritedGenericParameters;
            }

            if (enclosingFunction.Method != null && enclosingFunction.Method.Method != null)
            {
                var      functionIdentifier = enclosingFunction.Method.Method.Identifier;
                CacheSet localSignatureSet;

                if (LocalCachedSets.TryGetValue(functionIdentifier, out localSignatureSet))
                {
                    if (localSignatureSet.InterfaceMembers.TryGetValue(record, out index))
                    {
                        output.WriteRaw("$im{0:X2}", index);

                        return;
                    }
                }
            }

            if (!Global.InterfaceMembers.TryGetValue(record, out index))
            {
                output.Identifier(jsMethod.Reference.DeclaringType, referenceContext, false);
                output.Dot();
                astEmitter.Emit(method);
            }
            else
            {
                output.WriteRaw("$IM{0:X2}", index);
                output.LPar();
                if (rewrittenGenericParameters != null)
                {
                    output.CommaSeparatedList(rewrittenGenericParameters, referenceContext);
                }
                output.RPar();
            }
        }
Ejemplo n.º 7
0
 private static string GetMethodName(JSMethod method)
 {
     if (method == null)
     {
         return("?");
     }
     else
     {
         return(method.Reference.Name);
     }
 }
Ejemplo n.º 8
0
 public Invocation(
     int[] parentNodeIndices, int statementIndex, int nodeIndex,
     JSType type, JSMethod method,
     IDictionary <string, string[]> variables
     )
     : base(parentNodeIndices, statementIndex, nodeIndex)
 {
     ThisType     = type;
     ThisVariable = null;
     Method       = method;
     Variables    = variables;
 }
Ejemplo n.º 9
0
        public void VisitNode(JSMethod method)
        {
            Output.Identifier(method.GetNameForInstanceReference());

            var ga = method.GenericArguments;

            if (ga != null)
            {
                Output.LPar();
                Output.CommaSeparatedList(ga, ReferenceContext, ListValueType.Identifier);
                Output.RPar();
            }
        }
Ejemplo n.º 10
0
        public void VisitNode(JSMethod method)
        {
            var cm = GetCachedMethod(method);

            if (cm != null)
            {
                ParentNode.ReplaceChild(method, cm);
                VisitReplacement(cm);
            }
            else
            {
                VisitChildren(method);
            }
        }
Ejemplo n.º 11
0
        public void VisitNode(JSNewExpression newexp)
        {
            if ((newexp.ConstructorReference != null) && (newexp.Constructor != null))
            {
                var jsm       = new JSMethod(newexp.ConstructorReference, newexp.Constructor, FunctionSource.MethodTypes);
                var variables = ExtractAffectedVariables(jsm, newexp.Parameters);

                State.Invocations.Add(new FunctionAnalysis1stPass.Invocation(
                                          GetParentNodeIndices(), StatementIndex, NodeIndex, (JSVariable)null, jsm, newexp.ConstructorReference, variables
                                          ));
            }

            VisitChildren(newexp);
        }
Ejemplo n.º 12
0
 public Invocation(
     NodeIndices parentNodeIndices, int statementIndex, int nodeIndex,
     JSType type, JSMethod method, object nonJSMethod,
     Dictionary <string, ArraySegment <string> > variables
     )
     : base(parentNodeIndices, statementIndex, nodeIndex)
 {
     ThisType     = type;
     ThisVariable = null;
     Method       = method;
     if (method == null)
     {
         NonJSMethod = nonJSMethod;
     }
     else
     {
         NonJSMethod = null;
     }
     Variables = variables;
 }
Ejemplo n.º 13
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
                {
                    entry.SecondPass = new FunctionAnalysis2ndPass(this, GetFirstPass(id));
                }
            }

            return(entry.SecondPass);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Writes an interface member reference to the output.
        /// </summary>
        public void WriteInterfaceMemberToOutput(
            JavascriptFormatter output, Compiler.Extensibility.IAstEmitter astEmitter, JSFunctionExpression enclosingFunction,
            JSMethod jsMethod, JSExpression method,
            TypeReferenceContext referenceContext
            )
        {
            int index;
            var record = new CachedInterfaceMemberRecord(jsMethod.Reference.DeclaringType, jsMethod.Identifier);

            if ((enclosingFunction.Method != null) || (enclosingFunction.Method.Method != null))
            {
                var      functionIdentifier = enclosingFunction.Method.Method.Identifier;
                CacheSet localSignatureSet;

                if (LocalCachedSets.TryGetValue(functionIdentifier, out localSignatureSet))
                {
                    if (localSignatureSet.InterfaceMembers.TryGetValue(record, out index))
                    {
                        output.WriteRaw("$im{0:X2}", index);

                        return;
                    }
                }
            }

            if (!Global.InterfaceMembers.TryGetValue(record, out index))
            {
                output.Identifier(jsMethod.Reference.DeclaringType, referenceContext, false);
                output.Dot();
                astEmitter.Emit(method);
            }
            else
            {
                output.WriteRaw("$IM{0:X2}()", index);
            }
        }
Ejemplo n.º 15
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);
        }
Ejemplo n.º 16
0
        private static string GenerateMethodCall(ClassDeclarationSyntax classSyntax, JSMethod method, int argsLength)
        {
            var result = new StringBuilder();

            if (method.ReturnType != "void")
            {
                result.Append("return ");
            }
            if (!method.IsStatic)
            {
                result.Append($"(({classSyntax.Identifier.ToString()})thisObj).");
            }
            result.Append(method.MethodName);
            result.Append('(');

            int  skipCount   = 0;
            bool appendComma = false;

            if (method.HasEngineParameter)
            {
                appendComma = true;
                result.Append("engine");
                skipCount++;
            }
            if (method.HasThisObject)
            {
                if (appendComma)
                {
                    result.Append(", ");
                }
                appendComma = true;

                result.Append(ConvertTo($"thisObj", method.ThisObjectParameterType, null));
                skipCount++;
            }

            int argIndex = 0;

            foreach (var parameter in method.Parameters)
            {
                if (appendComma)
                {
                    result.Append(", ");
                }
                appendComma = true;

                if (argIndex < argsLength)
                {
                    result.Append(ConvertTo($"args[{argIndex}]", parameter.Type, parameter.DefaultValue, argIndex));
                }
                else
                {
                    // Pass through undefined.
                    if (parameter.DefaultValue != null)
                    {
                        result.Append(parameter.DefaultValue);
                    }
                    else
                    {
                        switch (parameter.Type)
                        {
                        case "object":
                            result.Append("Undefined.Value");
                            break;

                        case "bool":
                            result.Append("false");
                            break;

                        case "int":
                            result.Append("0");
                            break;

                        case "string":
                            result.Append("\"undefined\"");
                            break;

                        case "double":
                            result.Append($"double.NaN");
                            break;

                        case "ObjectInstance":
                        case "FunctionInstance":
                        case "ArrayBufferInstance":
                        case "SymbolInstance":
                            return("throw new JavaScriptException(engine, ErrorType.TypeError, \"undefined cannot be converted to an object\");");

                        case "object[]":
                            result.Append("new object[0]");
                            break;

                        case "string[]":
                            result.Append("new string[0]");
                            break;

                        case "double[]":
                            result.Append("new double[0]");
                            break;

                        default:
                            throw new InvalidOperationException($"Unsupported parameter type {parameter.Type}");
                        }
                    }
                }
                argIndex++;
            }
            result.Append(");");

            if (method.ReturnType == "void")
            {
                result.Append(" return Undefined.Value;");
            }
            return(result.ToString());
        }
Ejemplo n.º 17
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();
        }
Ejemplo n.º 18
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
                ));
 }
Ejemplo n.º 19
0
 public CachedMethodRecord(JSMethod method, int index)
 {
     Method = method;
     Index  = index;
 }
        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);
        }