public void BindUsage(ISeq <JST.Statement> statements, CST.Usage usage, TypePhase typePhase)
        {
            foreach (var kv in usage.Assemblies)
            {
                if (kv.Value > 1)
                {
                    if (!boundAssemblies.ContainsKey(kv.Key))
                    {
                        var e = env.JSTHelpers.DefaultResolveAssembly(this, kv.Key);
                        if (e != null)
                        {
                            if (env.DebugMode)
                            {
                                statements.Add(new JST.CommentStatement(kv.Key.ToString()));
                            }
                            var id = NameSupply.GenSym();
                            statements.Add(JST.Statement.Var(id, e));
                            boundAssemblies.Add(kv.Key, id.ToE());
                        }
                    }
                    // else: use outer binding
                }
                // else: inline expression as need it
            }

            foreach (var kv in usage.Types)
            {
                if (kv.Value > 1)
                {
                    var existing = default(ExpressionAndPhase);
                    var b        = boundTypes.TryGetValue(kv.Key, out existing);
                    if (!b || typePhase > existing.Phase)
                    {
                        var e = env.JSTHelpers.DefaultResolveType(this, kv.Key, typePhase);
                        if (e != null)
                        {
                            if (env.DebugMode)
                            {
                                statements.Add(new JST.CommentStatement(kv.Key.ToString()));
                            }
                            var id = NameSupply.GenSym();
                            statements.Add(JST.Statement.Var(id, e));
                            var updated = new ExpressionAndPhase(id.ToE(), typePhase);
                            if (b)
                            {
                                boundTypes[kv.Key] = updated;
                            }
                            else
                            {
                                boundTypes.Add(kv.Key, updated);
                            }
                        }
                    }
                    // else: use outer binding
                }
                // else: inline expression as need it
            }
        }
Example #2
0
        // ----------------------------------------------------------------------
        // Type structures
        // ----------------------------------------------------------------------

        // Collect usage statistics for all the types we'll need at phase 1:
        //  - Any type args to the base type constructor (for BaseType field)
        //  - All types which are assignable from this type (for Supertypes field)
        //  - All interface types for interface methods implemented implicitly or explicit by this type
        //    (will be subset of above supertypes, but we collect so as to see which types are used more than once).
        private CST.Usage CollectPhase1Usage()
        {
            var usage = new CST.Usage();

            foreach (var typeRef in TypeCompEnv.AllExtendedTypes().Concat(TypeCompEnv.AllImplementedTypes()))
                typeRef.AccumUsage(usage, true);

            var realTypeDef = TypeCompEnv.Type as CST.RealTypeDef;
            if (realTypeDef != null)
            {
                foreach (var kv in realTypeDef.SlotImplementations)
                {
                    if (kv.Key.DefiningType.Style(TypeCompEnv) is CST.IntNativeTypeStyle)
                        TypeCompEnv.SubstituteType(kv.Key.DefiningType).AccumUsage(usage, true);
                }
            }

            return usage;
        }
Example #3
0
 public void BindUsage(ISeq <JST.Statement> statements, CST.Usage usage)
 {
     BindMap
         (statements,
         usage.Assemblies,
         boundAssemblies,
         n => n.ToString(),
         n => env.JSTHelpers.DefaultResolveAssembly(this, n));
     BindMap
         (statements,
         usage.Types,
         boundTypes,
         t => t.ToString(),
         t => env.JSTHelpers.DefaultResolveType(this, t, TypePhase.Constructed));
     BindMap
         (statements,
         usage.VariablePointers,
         boundVariablePointers,
         id => String.Format("Pointer to {0}", id.Value),
         VariablePointerExpression);
 }
Example #4
0
        // For speed we inline rather than chain to base-type initialize object functions
        private JST.FunctionExpression ConstructObjectFunction()
        {
            var parameters = new Seq<JST.Identifier>();
            var innerBody = new Seq<JST.Statement>();

            if (TypeCompEnv.Type.Style is CST.ClassTypeStyle)
            {
                var fieldRefs = new Seq<CST.FieldRef>();
                AccumInstanceFields(TypeCompEnv, fieldRefs);

                var innerTypeCompEnv = TypeCompEnv.EnterFunction();

                var usage = new CST.Usage();
                var trivFieldRefs = new Seq<CST.FieldRef>();
                var nonTrivFieldRefs = new Seq<CST.FieldRef>();
                foreach (var fieldRef in fieldRefs)
                {
                    if (Env.JSTHelpers.DefaultFieldValueIsNonNull(innerTypeCompEnv, fieldRef))
                    {
                        nonTrivFieldRefs.Add(fieldRef);
                        fieldRef.ExternalFieldType.AccumUsage(usage, true);
                    }
                    else
                        trivFieldRefs.Add(fieldRef);
                }

                if (trivFieldRefs.Count + nonTrivFieldRefs.Count > 0)
                {
                    var suppressInitId = innerTypeCompEnv.NameSupply.GenSym();
                    parameters.Add(suppressInitId);

                    var ifBody = new Seq<JST.Statement>();

                    innerTypeCompEnv.BindUsage(ifBody, usage, TypePhase.Constructed);

                    var inst = default(JST.Expression);
                    if (trivFieldRefs.Count + nonTrivFieldRefs.Count > 1)
                    {
                        var instId = innerTypeCompEnv.NameSupply.GenSym();
                        ifBody.Add(JST.Statement.Var(instId, new JST.ThisExpression()));
                        inst = instId.ToE();
                    }
                    else
                        inst = new JST.ThisExpression();

                    foreach (var fieldRef in nonTrivFieldRefs)
                    {
                        ifBody.Add
                            (JST.Statement.DotAssignment
                                 (inst,
                                  Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, false),
                                  Env.JSTHelpers.DefaultFieldValue(innerTypeCompEnv, fieldRef)));
                    }

                    if (trivFieldRefs.Count > 0)
                    {
                        var assn = (JST.Expression)new JST.NullExpression();
                        foreach (var fieldRef in trivFieldRefs)
                        {
                            var fld = JST.Expression.Dot
                                (inst, Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, false));
                            assn = new JST.BinaryExpression(fld, JST.BinaryOp.Assignment, assn);
                        }
                        ifBody.Add(new JST.ExpressionStatement(assn));
                    }

                    // If constructor is being called to build a prototype object, don't initialize
                    // any field, since
                    //  - they aren't needed
                    //  - we can't access the field types yet
                    innerBody.Add(new JST.IfStatement(JST.Expression.Not(suppressInitId.ToE()), new JST.Statements(ifBody)));
                }
            }
            // else: for value types, the DefaultValue function is responsible for constructing values.
            // The ConstructObject function is used only when constructing pointers/boxes.

            return new JST.FunctionExpression(parameters, new JST.Statements(innerBody));
        }
Example #5
0
        // For speed we inline rather than chain to base-type default values
        // (Though, actually, that's not necessary since value types are sealed and have not inherited fields...)
        private void EmitDefaultValue(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var s = TypeCompEnv.Type.Style;
            var innerBody = new Seq<JST.Statement>();

            if (s is CST.VoidTypeStyle || s is CST.ManagedPointerTypeStyle)
                innerBody.Add
                    (new JST.ThrowStatement
                         (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException)));
            else if (s is CST.NumberTypeStyle || s is CST.EnumTypeStyle || TypeCompEnv.TypeRef.Equals(Env.Global.DecimalRef))
                innerBody.Add(new JST.ReturnStatement(new JST.NumericLiteral(0)));
            else if (s is CST.StructTypeStyle)
            {
                var allFieldRefs = new Seq<CST.FieldRef>();
                AccumInstanceFields(TypeCompEnv, allFieldRefs);

                var innerTypeCompEnv = TypeCompEnv.EnterFunction();

                var usage = new CST.Usage();
                foreach (var fieldRef in allFieldRefs)
                {
                    if (Env.JSTHelpers.DefaultFieldValueIsNonNull(innerTypeCompEnv, fieldRef))
                        fieldRef.ExternalFieldType.AccumUsage(usage, true);
                }
                innerTypeCompEnv.BindUsage(innerBody, usage, TypePhase.Constructed);

                var bindings = new OrdMap<JST.Identifier, JST.Expression>();
                foreach (var fieldRef in allFieldRefs)
                    bindings.Add
                        (Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, false),
                         Env.JSTHelpers.DefaultFieldValue(innerTypeCompEnv, fieldRef));

                innerBody.Add(new JST.ReturnStatement(new JST.ObjectLiteral(bindings)));
            }
            // else: default default value of null is ok

            if (innerBody.Count > 0)
                body.Add
                    (JST.Statement.DotAssignment
                         (lhs, Constants.TypeDefaultValue, new JST.FunctionExpression(null, new JST.Statements(innerBody))));
        }
Example #6
0
        // For speed we inline rather than chain to base-type clones
        private void EmitMemberwiseClone(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var s = TypeCompEnv.Type.Style;
            if (s is CST.ClassTypeStyle || s is CST.StructTypeStyle)
            {
                var fields = new Seq<CST.FieldRef>();
                AccumInstanceFields(TypeCompEnv, fields);
                var trivFields = new Seq<CST.FieldRef>();
                var nonTrivFields = new Seq<CST.FieldRef>();
                foreach (var fieldRef in fields)
                {
                    var fieldType = ((CST.FieldSignature)fieldRef.ExternalSignature).FieldType;
                    if (Env.JSTHelpers.CloneIsNonTrivial(TypeCompEnv, fieldType))
                        nonTrivFields.Add(fieldRef);
                    else
                        trivFields.Add(fieldRef);
                }

                if (nonTrivFields.Count > 0)
                {
                    var innerTypeCompEnv = TypeCompEnv.EnterFunction();

                    var parameters = new Seq<JST.Identifier>();
                    parameters.Add(innerTypeCompEnv.NameSupply.GenSym());
                    var oldObj = parameters[0].ToE();
                    var innerBody = new Seq<JST.Statement>();

                    var usage = new CST.Usage();
                    foreach (var fieldRef in nonTrivFields)
                        fieldRef.ExternalFieldType.AccumUsage(usage, true);
                    innerTypeCompEnv.BindUsage(innerBody, usage, TypePhase.Constructed);

                    var newObjId = innerTypeCompEnv.NameSupply.GenSym();
                    if (s is CST.ClassTypeStyle)
                        // Reference type, object Id is allocated lazily
                        innerBody.Add
                            (JST.Statement.Var
                                 (newObjId, JST.Expression.DotCall(TypeId.ToE(), Constants.TypeConstructObject)));
                    else
                        // Value type
                        innerBody.Add(JST.Statement.Var(newObjId, new JST.ObjectLiteral()));
                    var newObj = newObjId.ToE();

                    // Explicity clone non-trivial fields
                    foreach (var fieldRef in nonTrivFields)
                    {
                        var fieldId = Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, false);
                        innerBody.Add
                            (JST.Statement.DotAssignment
                                 (newObj,
                                  fieldId,
                                  Env.JSTHelpers.CloneExpressionForType
                                      (innerTypeCompEnv,
                                       fieldRef.ExternalFieldType,
                                       JST.Expression.Dot(oldObj, fieldId))));
                    }
                    if (trivFields.Count < 3)
                    {
                        // Explicity copy the remaining trivial fields
                        foreach (var fieldRef in trivFields)
                        {
                            var fieldId = Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, false);
                            innerBody.Add
                                (JST.Statement.DotAssignment(newObj, fieldId, JST.Expression.Dot(oldObj, fieldId)));
                        }
                    }
                    else
                    {
                        // Generically copy the remaining trivial fields
                        innerBody.Add
                            (JST.Statement.DotCall(RootId.ToE(), Constants.RootInheritProperties, newObj, oldObj));
                    }
                    innerBody.Add(new JST.ReturnStatement(newObj));

                    body.Add
                        (JST.Statement.DotAssignment
                             (lhs, Constants.TypeMemberwiseClone, new JST.FunctionExpression(parameters, new JST.Statements(innerBody))));
                }
                else
                {
                    // default generic clone with no inner cloning is ok
                    return;
                }
            }
            else
            {
                var innerNameSupply = NameSupply.Fork();
                var parameters = new Seq<JST.Identifier>();
                parameters.Add(innerNameSupply.GenSym());
                var oldObj = parameters[0].ToE();
                var innerBody = new Seq<JST.Statement>();

                if (s is CST.VoidTypeStyle)
                {
                    innerBody.Add
                        (new JST.ThrowStatement
                             (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException)));
                }
                else if (s is CST.ArrayTypeStyle)
                {
                    var newObjId = innerNameSupply.GenSym();
                    innerBody.Add
                        (JST.Statement.Var
                             (newObjId,
                              new JST.NewExpression
                                  (new JST.CallExpression
                                       (Constants.Array.ToE(), JST.Expression.Dot(oldObj, Constants.length)))));
                    innerBody.Add(JST.Statement.DotAssignment(newObjId.ToE(), Constants.ObjectType, TypeId.ToE()));
                    // Object Id is allocated lazily
                    var iId = innerNameSupply.GenSym();
                    var loopClause = new JST.ForVarLoopClause
                        (iId,
                         new JST.BinaryExpression
                             (iId.ToE(), JST.BinaryOp.LessThan, JST.Expression.Dot(oldObj, Constants.length)),
                         new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement));
                    var loopBody = JST.Statement.IndexAssignment
                        (newObjId.ToE(),
                         iId.ToE(),
                         Env.JSTHelpers.CloneExpressionForType
                             (TypeCompEnv,
                              TypeCompEnv.TypeBoundArguments[0],
                              new JST.IndexExpression(oldObj, iId.ToE())));
                    innerBody.Add(new JST.ForStatement(loopClause, new JST.Statements(loopBody)));
                    innerBody.Add(new JST.ReturnStatement(newObjId.ToE()));
                }
                else if (s is CST.NullableTypeStyle)
                {
                    innerBody.Add
                        (new JST.IfStatement
                             (JST.Expression.IsNull(oldObj),
                              new JST.Statements(new JST.ReturnStatement(new JST.NullExpression())),
                              new JST.Statements(new JST.ReturnStatement
                                  (Env.JSTHelpers.CloneExpressionForType
                                       (TypeCompEnv, TypeCompEnv.TypeBoundArguments[0], oldObj)))));
                }
                else
                {
                    innerBody.Add(new JST.ReturnStatement(oldObj));
                }

                body.Add
                    (JST.Statement.DotAssignment
                         (lhs, Constants.TypeMemberwiseClone, new JST.FunctionExpression(parameters, new JST.Statements(innerBody))));
            }
        }
Example #7
0
        private void EmitSetupType(Seq<JST.Statement> body, JST.Expression lhs)
        {
            // NOTE: We always emit the SetupType function, even if the body is empty, so that we can
            //       track which types are at phase 3. (We need to initialize base types and type arguments
            //       to phase 3 when type itself is brought up to phase 3.)

            // Collect static fields and their types
            // NOTE: We used to also bind null instance fields into the prototype, but this turns out to
            //       be a significant performance hit
            var staticFields = new Seq<CST.FieldRef>();
            var usage = new CST.Usage();
            foreach (var fieldDef in Parent.Fields.Where(f => f.IsStatic))
            {
                var fieldRef = new CST.FieldRef(TypeCompEnv.TypeRef, fieldDef.FieldSignature);
                if (TypeCompEnv.Type.Style is CST.EnumTypeStyle || fieldDef.Init == null ||
                    fieldDef.Init.Flavor != CST.FieldInitFlavor.Const)
                {
                    staticFields.Add(fieldRef);
                    if (Env.JSTHelpers.DefaultFieldValueIsNonNull(TypeCompEnv, fieldRef))
                        // We'll need type to construct default
                        fieldRef.ExternalFieldType.AccumUsage(usage, true);
                }
                // else: constant static fields, other than enums, don't need any run-time representation
            }

            var innerBody = new Seq<JST.Statement>();
            var innerTypeCompEnv = TypeCompEnv.EnterFunction();

            innerTypeCompEnv.BindUsage(innerBody, usage, TypePhase.Constructed);

            if (staticFields.Count > 0)
            {
                if (Env.DebugMode)
                    innerBody.Add(new JST.CommentStatement("Static fields"));
                foreach (var fieldRef in staticFields)
                {
                    innerBody.Add
                        (JST.Statement.DotAssignment
                             (TypeId.ToE(),
                              Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, true),
                              Env.JSTHelpers.DefaultFieldValue(innerTypeCompEnv, fieldRef)));
                }
            }

            if (Parent.StaticInitializer != null)
            {
                if (Env.DebugMode)
                    innerBody.Add(new JST.CommentStatement("Static constructor"));
                innerBody.Add
                    (new JST.ExpressionStatement
                         (innerTypeCompEnv.MethodCallExpression
                              (Parent.StaticInitializer, innerTypeCompEnv.NameSupply, false, JST.Constants.EmptyExpressions)));
            }

            EmitReflection(innerBody, innerTypeCompEnv, TypeId.ToE());

            body.Add
                (JST.Statement.DotAssignment
                     (lhs, Constants.TypeSetupType, new JST.FunctionExpression(null, new JST.Statements(innerBody))));
        }
Example #8
0
        private JST.FunctionExpression DelegateImporterExporter(bool isImporter)
        {
            var delTypeDef = (CST.DelegateTypeDef)TypeCompEnv.Type;
            var delInfo = Env.InteropManager.DelegateInfo(TypeCompEnv.Assembly, TypeCompEnv.Type);
            var func = isImporter ? Constants.RootDelegateImporter : Constants.RootDelegateExporter;

            var innerTypeCompEnv = TypeCompEnv.EnterFunction();
            var parameters = new Seq<JST.Identifier>();
            parameters.Add(innerTypeCompEnv.NameSupply.GenSym());
            var body = new Seq<JST.Statement>();

            var usage = new CST.Usage();
            foreach (var p in delTypeDef.ValueParameters)
                TypeCompEnv.SubstituteType(p.Type).AccumUsage(usage, true);
            if (delTypeDef.Result != null)
                TypeCompEnv.SubstituteType(delTypeDef.Result.Type).AccumUsage(usage, true);
            innerTypeCompEnv.BindUsage(body, usage, TypePhase.Constructed);

            body.Add
                (new JST.ReturnStatement
                     (JST.Expression.DotCall
                          (RootId.ToE(),
                           func,
                           TypeId.ToE(),
                           new JST.ArrayLiteral
                               (delTypeDef.ValueParameters.Select
                                    (p => innerTypeCompEnv.ResolveType(p.Type, TypePhase.Constructed)).ToSeq()),
                           delTypeDef.Result == null
                               ? new JST.NullExpression()
                               : innerTypeCompEnv.ResolveType(delTypeDef.Result.Type, TypePhase.Constructed),
                           new JST.BooleanLiteral(delInfo.IsCaptureThis),
                           new JST.BooleanLiteral(delInfo.IsInlineParamsArray),
                           parameters[0].ToE())));

            return new JST.FunctionExpression(parameters, new JST.Statements(body));
        }