Exemplo n.º 1
0
        protected override object VisitStoreField(Variable dest, Field field, Variable source, Statement stat, object arg)
        {
            ExposureState estate = (ExposureState)arg;

            // static Fields
            if (field.IsStatic)
            {
            }

            // BUGBUG!!
            // It seems that it would be better to start off ctors with the method's "this" object
            // in the Exposed state, but I'm not sure how to do that.
            This        t  = null;
            ThisBinding tb = dest as ThisBinding;

            if (tb != null)
            {
                t = tb.BoundThis;
            }
            else
            {
                t = dest as This;
            }
            if (t != null &&
                this.ExposureChecker.currentMethod.NodeType == NodeType.InstanceInitializer &&
                this.ExposureChecker.currentMethod.ThisParameter == t)
            {
                ; // skip
            }
            else
            {
                ExposureState.Lattice.AVal valueOfdest = estate.GetAVal(dest);
                if (valueOfdest.lowerBound == null || valueOfdest.upperBound == null)
                {
                    HandleError(stat, stat, Error.WritingPackedObject, dest.Name.Name);
                    return(arg);
                }
                if (valueOfdest.lowerBound.IsAssignableTo(field.DeclaringType))
                {
                    HandleError(stat, stat, Error.WritingPackedObject, dest.Name.Name);
                    return(arg);
                }
            }

            return(arg);
        }
Exemplo n.º 2
0
        private void ProcessMethod(StatementList setupInteropStatements, Set<DelegateNode> accumDelegateTypes, Method method)
        {
            try
            {
                if (env.InteropManager.IsImported(null, method))
                {
                    AddDelegateTypes(accumDelegateTypes, method);
                    //  If constructor:
                    //      C(A1 a1, A2 a2)
                    //  emit:
                    //      var ci = typeof(<this type>).GetConstructor(new Type[] { typeof(A1), typeof(A2) });
                    //      var ctxt = (JSContext)InteropContextManager.CurrentRuntime.CallImportedMethod(
                    //                                ci,
                    //                                <import script>,
                    //                                new object[] { this, a1, a2 });
                    //      C(ctxt, a1, a2) or C(ctxt);
                    //      InteropContextManager.CurrentRuntime.CompleteConstruction(ci, this, ctxt);
                    //
                    //  If static method:
                    //      R C::M(A1 a1, A2 a2)
                    //  emit:
                    //      return (R)InteropContextManager.CurrentRuntime.CallImportedMethod(
                    //                    typeof(<this type>).GetMethod("M", new Type[] { typeof(A1), typeof(A2) }),
                    //                    <import script>,
                    //                    new object[] { a1, a2 });
                    //
                    //  If instance method:
                    //      R C::M(A1 a1, A2 a2)
                    //  emit:
                    //      return (R)InteropContextManager.GetRuntimeForObject(this).CallImportedMethod(
                    //                    typeof(<this type>).GetMethod("M", new Type[] { typeof(A1), typeof(A2) }),
                    //                    <import script>,
                    //                    new object[] { this, a1, a2 });

                    var thisExpr = new ThisBinding(ThisExpression(method.DeclaringType), method.SourceContext);

                    var argExprs = new ExpressionList();
                    if (!method.IsStatic && !(method is InstanceInitializer))
                        argExprs.Add(thisExpr);
                    foreach (var p in method.Parameters)
                        argExprs.Add
                            (BoxExpression(new ParameterBinding(p, method.SourceContext), env.ObjectType));
                    var argArray = ArrayExpression(argExprs, env.ObjectType);

                    // Imports are special in a few ways:
                    //  - The runtime will never attempt to Invoke the method base. All it needs are the
                    //    argument types, static/instance distiction, and method/constructor distinction.
                    //  - The call to Runtime::CallImportedMethod will be within the method body
                    //    itself. If the method is polymorphic, and/or within a higher-kinded type, then
                    //    typeof(<argument type>) will yield the correct runtime type for the argument, taking
                    //    account of all type instantiation. We don't need to know the type arguments themselves.
                    //  - Private methods may be imported, however Silverlight doesn't provide reflection for
                    //    private methods.
                    // For these reasons we build our own simple-minded method base literal to support the
                    // CallImportedMethod call.
                    var methodBaseExpr = SimpleMethodBaseExpression(method);

                    var runtimeExpr = default(Expression);
                    if (method.IsStatic || method is InstanceInitializer)
                        runtimeExpr = new MethodCall
                            (new MemberBinding(null, env.InteropContextManager_GetCurrentRuntimeMethod),
                             new ExpressionList(0));
                    else
                        runtimeExpr = new MethodCall
                            (new MemberBinding(null, env.InteropContextManager_GetRuntimeForObjectMethod),
                             new ExpressionList(thisExpr));

                    var si = env.InteropManager.ImportInfo(null, env.GenSym, new JST.Identifier(env.Root), method);
                    var scriptString = si.Script.ToString(false);
                    env.Log(new InteropInfoMessage(RewriterMsgContext.Method(method), "Imported as: " + scriptString));
                    var scriptExpr = new Literal(scriptString, env.StringType);

                    var statements = method.Body.Statements;
                    var ctor = method as InstanceInitializer;
                    if (ctor != null)
                    {
                        var locals = ctor.LocalList;
                        if (locals == null)
                        {
                            locals = new LocalList(2);
                            ctor.LocalList = locals;
                        }
                        var constructorInfoLocal = new Local(Identifier.For("ci"), env.SimpleMethodBaseType);
                        locals.Add(constructorInfoLocal);
                        var contextLocal = new Local(Identifier.For("ctxt"), env.JSContextType);
                        locals.Add(contextLocal);
                        statements.Add
                            (new AssignmentStatement
                                 (new LocalBinding(constructorInfoLocal, ctor.SourceContext), methodBaseExpr));
                        statements.Add
                            (new AssignmentStatement
                                 (new LocalBinding(contextLocal, ctor.SourceContext),
                                  CastExpression
                                      (new MethodCall
                                           (new MemberBinding
                                                (runtimeExpr, env.Runtime_CallImportedMethodMethod),
                                            new ExpressionList
                                                (new LocalBinding(constructorInfoLocal, ctor.SourceContext),
                                                 scriptExpr,
                                                 argArray)),
                                       env.JSContextType)));
                        var importingCtor = BestImportingConstructor(ctor);
                        var args = new ExpressionList(importingCtor.Parameters.Count);
                        args.Add(new LocalBinding(contextLocal, ctor.SourceContext));
                        if (importingCtor.Parameters.Count > 1)
                        {
                            for (var i = 0; i < ctor.Parameters.Count; i++)
                                args.Add(new ParameterBinding(ctor.Parameters[i], ctor.SourceContext));
                        }
                        statements.Add
                            (new ExpressionStatement
                                 (new MethodCall(new MemberBinding(thisExpr, importingCtor), args)));
                        statements.Add
                            (new ExpressionStatement
                                 (new MethodCall
                                      (new MemberBinding(runtimeExpr, env.Runtime_CompleteConstructionMethod),
                                       new ExpressionList
                                           (new LocalBinding(constructorInfoLocal, ctor.SourceContext),
                                            thisExpr,
                                            new LocalBinding(contextLocal, ctor.SourceContext)))));
                        statements.Add(new Return());
                    }
                    else if (method.ReturnType == env.VoidType)
                    {
                        statements.Add
                            (new ExpressionStatement
                                 (new MethodCall
                                      (new MemberBinding(runtimeExpr, env.Runtime_CallImportedMethodMethod),
                                       new ExpressionList(methodBaseExpr, scriptExpr, argArray))));
                        statements.Add(new ExpressionStatement(new UnaryExpression(null, NodeType.Pop)));
                        statements.Add(new Return());
                    }
                    else
                    {
                        statements.Add
                            (new Return
                                 (CastExpression
                                      (new MethodCall
                                           (new MemberBinding
                                                (runtimeExpr, env.Runtime_CallImportedMethodMethod),
                                            new ExpressionList(methodBaseExpr, scriptExpr, argArray)),
                                       method.ReturnType)));
                    }

                    TagAsInteropGenerated(method);
                }

                if (env.InteropManager.IsExported(null, method))
                {
                    AddDelegateTypes(accumDelegateTypes, method);
                    // For each exported method, append to <Module>::SetupInterop()
                    //     InteropContextManager.Database.RegisterExport(<method base of M>, <bind to instance>, <cature this>, <export script>);

                    // Exports are special in a few ways:
                    //  - Polymorphic methods cannot be exported, so we never need to deal with them.
                    //  - The call to Runtime::RegisterExportMethod is outside of the method itself. For instance
                    //    methods, the declaring type may be higher-kinded, in which case we must recover the
                    //    type arguments from the type of the instance at runtime. Thus at compile-time we
                    //    must describe the method in it's higher-kinded declaring type.
                    //  - The runtime needs to be able to Invoke the method base.
                    // Thus we are forced to use true MethodBase, MethodInfo and ConstructorInfo, and work-around
                    // limitations of reflection.
                    var si = env.InteropManager.ExportInfo(null, env.GenSym, new JST.Identifier(env.Root), method);
                    var scriptString = si.Script.ToString(false);
                    env.Log(new InteropInfoMessage(RewriterMsgContext.Method(method), "Exported as: " + scriptString));
                    setupInteropStatements.Add
                        (new ExpressionStatement
                             (new MethodCall
                                  (new MemberBinding
                                       (DatabaseExpression(), env.InteropDatabase_RegisterExportMethod),
                                   new ExpressionList
                                       (MethodBaseExpression(method),
                                        new Literal(si.BindToInstance, env.BooleanType),
                                        new Literal(scriptString, env.StringType)))));
                }
            }
            catch (DefinitionException)
            {
                env.Log(new InvalidInteropMessage(RewriterMsgContext.Method(method), "Method contains interop specification errors"));
            }
        }
Exemplo n.º 3
0
        private void ProcessType(StatementList setupInteropStatements, Set<DelegateNode> accumDelegateTypes, TypeNode type)
        {
            try
            {
                var style = env.InteropManager.Style(null, type);
                if (style == InteropStyle.Delegate)
                {
                    var delType = (DelegateNode)type;
                    var di = env.InteropManager.DelegateInfo(null, delType);
                    env.Log(new InteropInfoMessage(RewriterMsgContext.Type(type), "Registering type as: " + style));
                    setupInteropStatements.Add
                        (new ExpressionStatement
                             (new MethodCall
                                  (new MemberBinding
                                       (DatabaseExpression(), env.InteropDatabase_RegisterTypeMethod),
                                   new ExpressionList
                                       (TypeOfExpression(type),
                                        new Literal((int)style, env.IntType),
                                        new Literal(null, env.StringType),
                                        new Literal(null, env.StringType),
                                        new Literal(0, env.IntType),
                                        new Literal(di.CaptureThis, env.BooleanType),
                                        new Literal(di.InlineParamsArray, env.BooleanType),
                                        new Literal(false, env.BooleanType)))));
                }
                else if (style == InteropStyle.Proxied || style == InteropStyle.Keyed)
                {
                    // Append to <Module>::SetupInterop():
                    //     InteropContextManager.Database.RegisterType(
                    //         <index of type>,
                    //         Keyed or Proxied,
                    //         <JavaScript fragment for key field, or null>,
                    //         <JavaScript type classifier function, or null>,
                    //         <steps to root type>,
                    //         false);
                    var rootTypeSteps = env.InteropManager.RootTypeSteps(null, type);
                    var undefinedIsNotNull = false;
                    var keyFieldStr = default(string);
                    var classifierStr = default(string);
                    if (rootTypeSteps == 0)
                    {
                        if (style == InteropStyle.Keyed)
                            keyFieldStr = env.InteropManager.KeyField(null, type).ToString(false);
                        var classifierJS = env.InteropManager.TypeClassifier(null, type);
                        classifierStr = classifierJS == null ? null : classifierJS.ToString(false);
                    }
                    if (style == InteropStyle.Proxied)
                        undefinedIsNotNull = env.InteropManager.UndefinedIsNotNull(null, type);
                    env.Log(new InteropInfoMessage(RewriterMsgContext.Type(type), "Registering type as: " + style.ToString()));
                    setupInteropStatements.Add
                        (new ExpressionStatement
                             (new MethodCall
                                  (new MemberBinding
                                       (DatabaseExpression(), env.InteropDatabase_RegisterTypeMethod),
                                   new ExpressionList
                                       (TypeOfExpression(type),
                                        new Literal((int)style, env.IntType),
                                        new Literal(keyFieldStr, env.StringType),
                                        new Literal(classifierStr, env.StringType),
                                        new Literal(rootTypeSteps, env.IntType),
                                        new Literal(false, env.BooleanType),
                                        new Literal(false, env.BooleanType),
                                        new Literal(undefinedIsNotNull, env.BooleanType)))));

                    // Create default importing constructor if none supplied by user
                    //  - If derive from base with default importing constructor, invoke that.
                    //  - If derive from 'Normal' base with default constructor, invoke that.
                    //  - Otherwise error
                    var importingCtor = DefaultImportingConstructor(type);
                    if (importingCtor == null)
                    {
                        var thisExpr = new ThisBinding(ThisExpression(type), type.SourceContext);
                        var parameters = new ParameterList(1);
                        parameters.Add(new Parameter(Identifier.For("ctxt"), env.JSContextType));
                        var statements = new StatementList(1);
                        var baseType = type.BaseType;
                        if (baseType == null)
                            // Object is 'Normal', so this is never possible
                            throw new InvalidOperationException("no base type");
                        var baseDefaultImportingCtor = DefaultImportingConstructor(baseType);
                        if (baseDefaultImportingCtor != null)
                        {
                            env.Log(new InteropInfoMessage(RewriterMsgContext.Type(type),
                                 "Created default importing constructor chained from base type's default importing constructor"));
                            statements.Add
                                (new ExpressionStatement
                                     (new MethodCall
                                          (new MemberBinding(thisExpr, baseDefaultImportingCtor),
                                           new ExpressionList
                                               (new ParameterBinding(parameters[0], type.SourceContext)))));
                        }
                        else
                        {
                            if (env.InteropManager.Style(null, baseType) == InteropStyle.Normal)
                            {
                                var baseDefaultCtor = baseType.GetConstructor();
                                if (baseDefaultCtor == null)
                                {
                                    env.Log(new InteropInfoMessage
                                        (RewriterMsgContext.Type(type),
                                         "Cannot create a default importing constructor for type, since it derives from a type with state 'ManagedOnly' which does not contain a default constructor"));
                                    throw new DefinitionException();
                                }
                                env.Log(new InteropInfoMessage(RewriterMsgContext.Type(type),
                                     "Created default importing constructor chained from base type's default constructor"));
                                statements.Add
                                    (new ExpressionStatement
                                         (new MethodCall
                                              (new MemberBinding(thisExpr, baseDefaultCtor), new ExpressionList(0))));
                            }
                            else
                            {
                                var hkType = default(TypeNode);
                                var classTypeArguments = default(Seq<TypeNode>);
                                ExplodeTypeApplication(baseType, out hkType, out classTypeArguments);
                                if (classTypeArguments != null && classTypeArguments.Count > 0)
                                {
                                    env.Log(new InteropInfoMessage
                                        (RewriterMsgContext.Type(type),
                                         "Cannot create a default importing constructor for type, since it derives from an instance of a higher-kinded type without an explicit default importing constructor. (This limitation will be removed in the future.)"));
                                }
                                else
                                {
                                    env.Log(new InteropInfoMessage
                                        (RewriterMsgContext.Type(type),
                                         "Cannot create a default importing constructor for type, since it derives from a type with state 'ManagedAndJavaScript' or 'JavaScriptOnly', and that type does not contain a default importing constructor"));
                                }
                                throw new DefinitionException();
                            }
                        }
                        statements.Add(new Return());
                        importingCtor = new InstanceInitializer
                            (type, new AttributeList(0), parameters, new Block(statements));
                        importingCtor.Flags |= MethodFlags.Public;
                        importingCtor.DeclaringType = type;
                        TagAsCompilerGenerated(importingCtor);
                        // il2jsc can compile this importing ctor as if it were written by the user,
                        // so no need for any 'InteropGenerated' attribute.
                        type.Members.Add(importingCtor);
                    }
                }

                // Remember: a type containing only static imports/exports may appear 'Normal'
                if (style == InteropStyle.Normal || style == InteropStyle.Primitive || style == InteropStyle.Proxied || style == InteropStyle.Keyed)
                {
                    foreach (var member in type.Members)
                    {
                        var nestedType = member as TypeNode;
                        if (nestedType != null)
                            ProcessType(setupInteropStatements, accumDelegateTypes, nestedType);
                        else
                        {
                            var method = member as Method;
                            if (method != null)
                                ProcessMethod(setupInteropStatements, accumDelegateTypes, method);
                        }
                    }
                }

            }
            catch (DefinitionException)
            {
                env.Log(new InvalidInteropMessage(RewriterMsgContext.Type(type), "Type contains interop specification errors"));
            }
        }