Exemple #1
0
        private JSExpression ComputeAddress(
            JSExpression pointer, JSExpression offsetInElements, JSExpression offsetInBytes,
            out TypeReference elementType
            )
        {
            var pointerType = pointer.GetActualType(TypeSystem);

            elementType = pointerType.GetElementType();
            var elementSize = WasmUtil.SizeOfType(elementType);

            if (
                (offsetInElements != null) &&
                // I'm so helpful :-)))))
                (offsetInBytes == null)
                )
            {
                offsetInBytes = new JSBinaryOperatorExpression(
                    JSOperator.Multiply,
                    offsetInElements,
                    JSLiteral.New(elementSize),
                    pointerType
                    );
            }

            if (offsetInBytes != null)
            {
                var result = new JSPointerAddExpression(pointer, offsetInBytes, false);
                // Console.WriteLine("Constructing pae {0} from {1} {2} {3}", result, pointer, offsetInElements, offsetInBytes);
                return(result);
            }
            else
            {
                return(pointer);
            }
        }
Exemple #2
0
        public void NodeChildren () {
            var de = new JSDotExpression(JSLiteral.New(1), new JSStringIdentifier("2"));
            var boe = new JSBinaryOperatorExpression(JSOperator.Add, JSLiteral.New(1), JSLiteral.New(2), T1);

            Assert.AreEqual(2, de.Children.Count());
            Assert.AreEqual(2, boe.Children.Count());
        }
Exemple #3
0
        public static JSExpression[] GetArrayDimensions(TypeReference arrayType)
        {
            var at = arrayType as ArrayType;

            if (at == null)
            {
                return(null);
            }

            var result = new List <JSExpression>();

            for (var i = 0; i < at.Dimensions.Count; i++)
            {
                var dim = at.Dimensions[i];
                if (dim.IsSized)
                {
                    result.Add(JSLiteral.New(dim.UpperBound.Value));
                }
                else
                {
                    return(null);
                }
            }

            return(result.ToArray());
        }
Exemple #4
0
        private static JSExpression Mul(TypeSystem typeSystem, JSExpression lhs, JSExpression rhs)
        {
            long iLhs, iRhs;

            if (ExtractLiteral(lhs, out iLhs) && ExtractLiteral(rhs, out iRhs))
            {
                return(JSLiteral.New((int)(iLhs * iRhs)));
            }

            return(new JSBinaryOperatorExpression(JSOperator.Multiply, lhs, rhs, typeSystem.Int32));
        }
Exemple #5
0
 public JSExpression TranslateAttributeConstructorArgument(
     TypeSystem typeSystem, TypeReference context, CustomAttributeArgument ca
     )
 {
     if (ca.Value == null)
     {
         return(JSLiteral.Null(ca.Type));
     }
     else if (ca.Value is CustomAttributeArgument)
     {
         // :|
         return(TranslateAttributeConstructorArgument(
                    typeSystem, context, (CustomAttributeArgument)ca.Value
                    ));
     }
     else if (ca.Value is CustomAttributeArgument[])
     {
         // Issue #141. WTF.
         var valueArray = (CustomAttributeArgument[])ca.Value;
         return(new JSArrayExpression(typeSystem.Object,
                                      (from value in valueArray select TranslateAttributeConstructorArgument(
                                           typeSystem, context, value
                                           )).ToArray()
                                      ));
     }
     else if (ca.Type.FullName == "System.Type")
     {
         return(new JSTypeOfExpression((TypeReference)ca.Value));
     }
     else if (TypeUtil.IsEnum(ca.Type))
     {
         var longValue = Convert.ToInt64(ca.Value);
         var result    = JSEnumLiteral.TryCreate(
             _TypeInfoProvider.GetExisting(ca.Type),
             longValue
             );
         if (result != null)
         {
             return(result);
         }
         else
         {
             return(JSLiteral.New(longValue));
         }
     }
     else
     {
         try {
             return(JSLiteral.New(ca.Value as dynamic));
         } catch (Exception) {
             throw new NotImplementedException(String.Format("Attribute arguments of type '{0}' are not implemented.", ca.Type.FullName));
         }
     }
 }
Exemple #6
0
        private static JSExpression Add(TypeSystem typeSystem, JSExpression lhs, JSExpression rhs)
        {
            long iLhs, iRhs;

            if (ExtractLiteral(lhs, out iLhs) && ExtractLiteral(rhs, out iRhs))
            {
                return(JSLiteral.New((int)(iLhs + iRhs)));
            }

            var type = lhs.GetActualType(typeSystem);

            return(new JSBinaryOperatorExpression(JSOperator.Add, lhs, rhs, type));
        }
Exemple #7
0
        private JSBinaryOperatorExpression MakeUnaryMutation(
            JSExpression expressionToMutate, JSBinaryOperator mutationOperator,
            TypeReference type
            )
        {
            var newValue = new JSBinaryOperatorExpression(
                mutationOperator, expressionToMutate, JSLiteral.New(1),
                type
                );
            var assignment = new JSBinaryOperatorExpression(
                JSOperator.Assignment,
                expressionToMutate, newValue, type
                );

            return(assignment);
        }
Exemple #8
0
        public void NewArrayTraversal () {
            var na = new JSNewArrayExpression(
                T1,
                new JSExpression[] { JSLiteral.New(2) },
                new JSArrayExpression(
                    T1, 
                    JSLiteral.New(3),
                    JSLiteral.New(4)
                )
            );

            // DumpNodeSequence(na.SelfAndChildrenRecursive);
            DumpNodeSequence(na.AllChildrenRecursive);

            Assert.AreEqual(2, na.Children.ToArray().Length, "Child count");
            Assert.AreEqual(4, na.AllChildrenRecursive.ToArray().Length, "Recursive child count");
        }
Exemple #9
0
        public static JSBinaryOperatorExpression MakeUnaryMutation(
            JSExpression expressionToMutate, JSBinaryOperator mutationOperator,
            TypeReference type, TypeSystem typeSystem
            )
        {
            var newValue = new JSBinaryOperatorExpression(
                mutationOperator, expressionToMutate, JSLiteral.New(1),
                type
                );
            var assignment = new JSBinaryOperatorExpression(
                JSOperator.Assignment,
                MakeLhsForAssignment(expressionToMutate), newValue, type
                );

            assignment = ConvertReadExpressionToWriteExpression(assignment, typeSystem);

            return(assignment);
        }
        public void VisitNode(JSUnaryOperatorExpression uoe)
        {
            JSUnaryMutationOperator op;
            JSExpression            target;
            TypeReference           type;

            if (UnpackUnaryMutation(uoe, out op, out target, out type))
            {
                var tempVar = TemporaryVariable.ForFunction(
                    Stack.Last() as JSFunctionExpression, type
                    );
                var store = new JSBinaryOperatorExpression(
                    JSOperator.Assignment, tempVar, target, type
                    );

                var delta = (
                    (op == JSOperator.PostIncrement) ||
                    (op == JSOperator.PreIncrement)
                    )
                    ? 1
                    : -1;

                JSExpression replacement;
                if (
                    (op == JSOperator.PostIncrement) ||
                    (op == JSOperator.PostDecrement)
                    )
                {
                    var mutated = new JSPointerAddExpression(target, JSLiteral.New(delta), false);
                    replacement = new JSCommaExpression(store, mutated, tempVar);
                }
                else
                {
                    replacement = new JSPointerAddExpression(target, JSLiteral.New(delta), true);
                }

                ParentNode.ReplaceChild(uoe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(uoe);
        }
Exemple #11
0
 protected JSInvocationExpression CastToInteger(JSExpression charExpression)
 {
     return(JSInvocationExpression.InvokeMethod(
                JS.charCodeAt, charExpression, new[] { JSLiteral.New(0) }, true
                ));
 }
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType  = boe.Left.GetActualType(TypeSystem);
            var rightType = boe.Right.GetActualType(TypeSystem);

            // We can end up with a pointer literal in an arithmetic expression.
            // In this case we want to switch it back to a normal integer literal so that the math operations work.
            var leftPointer  = boe.Left as JSPointerLiteral;
            var rightPointer = boe.Right as JSPointerLiteral;

            if (!(boe.Operator is JSAssignmentOperator))
            {
                if (leftPointer != null)
                {
                    boe.ReplaceChild(boe.Left, JSLiteral.New(leftPointer.Value));
                }
                if (rightPointer != null)
                {
                    boe.ReplaceChild(boe.Right, JSLiteral.New(rightPointer.Value));
                }
            }

            JSExpression replacement = null;

            if (leftType.IsPointer && TypeUtil.IsIntegral(rightType))
            {
                if (
                    (boe.Operator == JSOperator.Add) ||
                    (boe.Operator == JSOperator.AddAssignment)
                    )
                {
                    replacement = new JSPointerAddExpression(
                        boe.Left, boe.Right,
                        boe.Operator == JSOperator.AddAssignment
                        );
                }
                else if (
                    (boe.Operator == JSOperator.Subtract) ||
                    (boe.Operator == JSOperator.SubtractAssignment)
                    )
                {
                    // FIXME: Int32 is probably wrong
                    replacement = new JSPointerAddExpression(
                        boe.Left,
                        new JSUnaryOperatorExpression(JSOperator.Negation, boe.Right, TypeSystem.Int32),
                        boe.Operator == JSOperator.SubtractAssignment
                        );
                }
            }
            else if (leftType.IsPointer && rightType.IsPointer)
            {
                if (boe.Operator == JSOperator.Subtract)
                {
                    // FIXME: Int32 is probably wrong
                    replacement = new JSPointerDeltaExpression(
                        boe.Left, boe.Right, TypeSystem.Int32
                        );
                }
                else if (boe.Operator is JSComparisonOperator)
                {
                    replacement = new JSPointerComparisonExpression(boe.Operator, boe.Left, boe.Right, boe.ActualType);
                }
            }

            if (replacement != null)
            {
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
            }
            else
            {
                VisitChildren(boe);
            }
        }
Exemple #13
0
        private void EmitFieldIntrinsics(int heapSize)
        {
            // FIXME: Gross
            var tis = (ITypeInfoSource)Translator.TypeInfoProvider;

            Formatter.WriteRaw(";; Compiler-generated field accessors");
            Formatter.NewLine();

            foreach (var kvp in FieldTable.OrderBy(kvp => kvp.Value.Offset))
            {
                var fd         = kvp.Value.Field;
                var fi         = (FieldInfo)tis.Get(fd);
                var name       = WasmUtil.FormatMemberName(fi.Member);
                var typeSystem = fd.FieldType.Module.TypeSystem;

                // HACK
                var baseAddressParam = new JSVariable("address", typeSystem.Int32, null);
                // HACK
                var valueParam = new JSVariable("value", fd.FieldType, null);

                JSExpression address;
                if (fd.IsStatic)
                {
                    address = JSLiteral.New(kvp.Value.Offset + heapSize);
                }
                else
                {
                    address = new JSBinaryOperatorExpression(
                        JSOperator.Add,
                        baseAddressParam,
                        JSLiteral.New(kvp.Value.Offset),
                        typeSystem.Int32
                        );
                }

                Formatter.ConditionalNewLine();
                Formatter.WriteRaw(
                    "(func $__get_{0} (result {1}){2}(return ",
                    name,
                    WasmUtil.PickTypeKeyword(fd.FieldType),
                    fd.IsStatic
                        ? " "
                        : " (param $address i32) "
                    );

                var gm = new GetMemory(
                    fd.FieldType, /* FIXME: Align addresses */ false,
                    address
                    );

                // HACK
                EntryPointAstEmitter.Emit(gm);

                Formatter.WriteRaw(") )");

                if (fd.IsInitOnly)
                {
                    continue;
                }

                Formatter.NewLine();
                Formatter.WriteRaw(
                    "(func $__set_{0}{2}(param $value {1}) ",
                    name,
                    WasmUtil.PickTypeKeyword(fd.FieldType),
                    fd.IsStatic
                        ? " "
                        : " (param $address i32) "
                    );
                Formatter.Indent();
                Formatter.NewLine();
                var sm = new SetMemory(
                    fd.FieldType, /* FIXME: Align addresses */ false,
                    address, valueParam
                    );

                // HACK
                EntryPointAstEmitter.Emit(sm);

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

            Formatter.NewLine();
            Formatter.NewLine();
        }
        private JSForLoop ReplaceWhileLoopAndEnumerator(JSWhileLoop wl, JSExpression backingStore, JSExpression enumerator, TypeInfo enumeratorType, string arrayMember, string lengthMember)
        {
            var loopId             = _NextLoopId++;
            var arrayVariableName  = String.Format("a${0:x}", loopId);
            var indexVariableName  = String.Format("i${0:x}", loopId);
            var lengthVariableName = String.Format("l${0:x}", loopId);

            var currentPropertyReference = enumeratorType.Definition.Properties.First((p) => p.Name == "Current");
            var currentPropertyInfo      = enumeratorType.Source.GetProperty(currentPropertyReference);

            var itemType  = currentPropertyInfo.ReturnType;
            var arrayType = new ArrayType(itemType);

            var arrayVariable = new JSVariable(
                arrayVariableName, arrayType, Function.Method.Reference,
                JSDotExpression.New(backingStore, new JSStringIdentifier(arrayMember, arrayType))
                );
            var indexVariable = new JSVariable(
                indexVariableName, TypeSystem.Int32, Function.Method.Reference,
                JSLiteral.New(0)
                );
            var lengthVariable = new JSVariable(
                lengthVariableName, TypeSystem.Int32, Function.Method.Reference,
                JSDotExpression.New(backingStore, new JSStringIdentifier(lengthMember, TypeSystem.Int32))
                );

            var initializer = new JSVariableDeclarationStatement(
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, arrayVariable, arrayVariable.DefaultValue, arrayVariable.IdentifierType
                    ),
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, indexVariable, indexVariable.DefaultValue, indexVariable.IdentifierType
                    ),
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, lengthVariable, lengthVariable.DefaultValue, lengthVariable.IdentifierType
                    )
                );

            var condition = new JSBinaryOperatorExpression(
                JSOperator.LessThan,
                indexVariable, lengthVariable, TypeSystem.Boolean
                );

            var increment = new JSUnaryOperatorExpression(
                JSOperator.PostIncrement,
                indexVariable, TypeSystem.Int32
                );

            var result = new JSForLoop(
                initializer, condition, new JSExpressionStatement(increment),
                wl.Statements.ToArray()
                );

            result.Index = wl.Index;

            new PropertyAccessReplacer(
                enumerator, new JSProperty(currentPropertyReference, currentPropertyInfo),
                new JSIndexerExpression(
                    arrayVariable, indexVariable,
                    itemType
                    )
                ).Visit(result);

            return(result);
        }
Exemple #15
0
        public void VisitNode(JSCastExpression ce)
        {
            var currentType = ce.Expression.GetActualType(TypeSystem);
            var targetType  = ce.NewType;

            JSExpression newExpression = null;

            if (targetType.MetadataType == MetadataType.Char)
            {
                newExpression = JSInvocationExpression.InvokeStatic(
                    JS.fromCharCode, new[] { ce.Expression }, true
                    );
            }
            else if (
                (currentType.MetadataType == MetadataType.Char) &&
                TypeUtil.IsIntegral(targetType)
                )
            {
                newExpression = JSInvocationExpression.InvokeMethod(
                    JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true
                    );
            }
            else if (
                IntroduceEnumCasts.IsEnumOrNullableEnum(currentType)
                )
            {
                var enumInfo = TypeInfo.Get(currentType);

                if (targetType.MetadataType == MetadataType.Boolean)
                {
                    EnumMemberInfo enumMember;
                    if (enumInfo.ValueToEnumMember.TryGetValue(0, out enumMember))
                    {
                        newExpression = new JSBinaryOperatorExpression(
                            JSOperator.NotEqual, ce.Expression,
                            new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean
                            );
                    }
                    else if (enumInfo.ValueToEnumMember.TryGetValue(1, out enumMember))
                    {
                        newExpression = new JSBinaryOperatorExpression(
                            JSOperator.Equal, ce.Expression,
                            new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean
                            );
                    }
                    else
                    {
                        newExpression = new JSUntranslatableExpression(String.Format(
                                                                           "Could not cast enum of type '{0}' to boolean because it has no zero value or one value",
                                                                           currentType.FullName
                                                                           ));
                    }
                }
                else if (TypeUtil.IsNumeric(targetType))
                {
                    newExpression = JSInvocationExpression.InvokeStatic(
                        JS.Number(targetType), new[] { ce.Expression }, true
                        );
                }
                else if (targetType.FullName == "System.Enum")
                {
                    newExpression = ce.Expression;
                }
                else
                {
                    // Debugger.Break();
                }
            }
            else if (
                targetType.MetadataType == MetadataType.Boolean
                )
            {
                newExpression = new JSBinaryOperatorExpression(
                    JSBinaryOperator.NotEqual,
                    ce.Expression, new JSDefaultValueLiteral(currentType),
                    TypeSystem.Boolean
                    );
            }
            else if (
                TypeUtil.IsNumeric(targetType) &&
                TypeUtil.IsNumeric(currentType)
                )
            {
                if (
                    TypeUtil.IsIntegral(currentType) ||
                    !TypeUtil.IsIntegral(targetType)
                    )
                {
                    newExpression = ce.Expression;
                }
                else
                {
                    newExpression = JSInvocationExpression.InvokeStatic(JS.floor, new[] { ce.Expression }, true);
                }
            }
            else
            {
                newExpression = JSIL.Cast(ce.Expression, targetType);
            }

            if (newExpression != null)
            {
                ParentNode.ReplaceChild(ce, newExpression);
                VisitReplacement(newExpression);
            }
            else
            {
                // Debugger.Break();
                VisitChildren(ce);
            }
        }
Exemple #16
0
        public void VisitNode(JSInvocationExpression ie)
        {
            var type           = ie.JSType;
            var method         = ie.JSMethod;
            var thisExpression = ie.ThisReference;

            if (method != null)
            {
                if (
                    (type != null) &&
                    (type.Type.FullName == "System.Object")
                    )
                {
                    switch (method.Method.Member.Name)
                    {
                    case ".ctor": {
                        var replacement = new JSNullExpression();
                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }

                    case "GetType": {
                        JSNode replacement;

                        var thisType = JSExpression.DeReferenceType(thisExpression.GetActualType(TypeSystem), false);
                        if ((thisType is GenericInstanceType) && thisType.FullName.StartsWith("System.Nullable"))
                        {
                            replacement = new JSType(thisType);
                        }
                        else
                        {
                            replacement = JSIL.GetTypeOf(thisExpression);
                        }

                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }
                    }
                }
                else if (
                    IsNullable(type.Type)
                    )
                {
                    var t        = (type.Type as GenericInstanceType).GenericArguments[0];
                    var @null    = JSLiteral.Null(t);
                    var @default = new JSDefaultValueLiteral(t);

                    switch (method.Method.Member.Name)
                    {
                    case ".ctor":
                        JSExpression value;
                        if (ie.Arguments.Count == 0)
                        {
                            value = @null;
                        }
                        else
                        {
                            value = ie.Arguments[0];
                        }

                        var boe = new JSBinaryOperatorExpression(
                            JSOperator.Assignment, ie.ThisReference, value, type.Type
                            );
                        ParentNode.ReplaceChild(ie, boe);
                        VisitReplacement(boe);

                        break;

                    case "GetValueOrDefault":
                        var isNull = new JSBinaryOperatorExpression(
                            JSOperator.Equal, ie.ThisReference, @null, TypeSystem.Boolean
                            );

                        JSTernaryOperatorExpression ternary;
                        if (ie.Arguments.Count == 0)
                        {
                            ternary = new JSTernaryOperatorExpression(
                                isNull, @default, ie.ThisReference, type.Type
                                );
                        }
                        else
                        {
                            ternary = new JSTernaryOperatorExpression(
                                isNull, ie.Arguments[0], ie.ThisReference, type.Type
                                );
                        }

                        ParentNode.ReplaceChild(ie, ternary);
                        VisitReplacement(ternary);

                        break;

                    default:
                        throw new NotImplementedException(method.Method.Member.FullName);
                    }

                    return;
                }
                else if (
                    (type != null) &&
                    TypeUtil.TypesAreEqual(TypeSystem.String, type.Type) &&
                    (method.Method.Name == "Concat")
                    )
                {
                    if (ie.Arguments.Count > 2)
                    {
                        if (ie.Arguments.All(
                                (arg) => TypeUtil.TypesAreEqual(
                                    TypeSystem.String, arg.GetActualType(TypeSystem)
                                    )
                                ))
                        {
                            var boe = JSBinaryOperatorExpression.New(
                                JSOperator.Add,
                                ie.Arguments,
                                TypeSystem.String
                                );

                            ParentNode.ReplaceChild(
                                ie,
                                boe
                                );

                            VisitReplacement(boe);
                        }
                    }
                    else if (
                        ie.Arguments.Count == 2
                        )
                    {
                        var lhs     = ie.Arguments[0];
                        var lhsType = TypeUtil.DereferenceType(lhs.GetActualType(TypeSystem));
                        if (!(
                                TypeUtil.TypesAreEqual(TypeSystem.String, lhsType) ||
                                TypeUtil.TypesAreEqual(TypeSystem.Char, lhsType)
                                ))
                        {
                            lhs = JSInvocationExpression.InvokeMethod(lhsType, JS.toString, lhs, null);
                        }

                        var rhs     = ie.Arguments[1];
                        var rhsType = TypeUtil.DereferenceType(rhs.GetActualType(TypeSystem));
                        if (!(
                                TypeUtil.TypesAreEqual(TypeSystem.String, rhsType) ||
                                TypeUtil.TypesAreEqual(TypeSystem.Char, rhsType)
                                ))
                        {
                            rhs = JSInvocationExpression.InvokeMethod(rhsType, JS.toString, rhs, null);
                        }

                        var boe = new JSBinaryOperatorExpression(
                            JSOperator.Add, lhs, rhs, TypeSystem.String
                            );

                        ParentNode.ReplaceChild(
                            ie, boe
                            );

                        VisitReplacement(boe);
                    }
                    else if (
                        TypeUtil.GetTypeDefinition(ie.Arguments[0].GetActualType(TypeSystem)).FullName == "System.Array"
                        )
                    {
                    }
                    else
                    {
                        var firstArg = ie.Arguments.FirstOrDefault();

                        ParentNode.ReplaceChild(
                            ie, firstArg
                            );

                        if (firstArg != null)
                        {
                            VisitReplacement(firstArg);
                        }
                    }
                    return;
                }
                else if (
                    TypeUtil.IsDelegateType(method.Reference.DeclaringType) &&
                    (method.Method.Name == "Invoke")
                    )
                {
                    var newIe = new JSDelegateInvocationExpression(
                        thisExpression, ie.GetActualType(TypeSystem), ie.Arguments.ToArray()
                        );
                    ParentNode.ReplaceChild(ie, newIe);

                    VisitReplacement(newIe);
                    return;
                }
                else if (
                    (method.Reference.DeclaringType.FullName == "System.Type") &&
                    (method.Method.Name == "GetTypeFromHandle")
                    )
                {
                    var typeObj = ie.Arguments.FirstOrDefault();
                    ParentNode.ReplaceChild(ie, typeObj);

                    VisitReplacement(typeObj);
                    return;
                }
                else if (
                    (method.Reference.DeclaringType.Name == "RuntimeHelpers") &&
                    (method.Method.Name == "InitializeArray")
                    )
                {
                    var array       = ie.Arguments[0];
                    var arrayType   = array.GetActualType(TypeSystem);
                    var field       = ie.Arguments[1].SelfAndChildrenRecursive.OfType <JSField>().First();
                    var initializer = JSArrayExpression.UnpackArrayInitializer(arrayType, field.Field.Member.InitialValue);

                    var copy = JSIL.ShallowCopy(array, initializer, arrayType);
                    ParentNode.ReplaceChild(ie, copy);
                    VisitReplacement(copy);
                    return;
                }
                else if (
                    method.Reference.DeclaringType.FullName == "System.Reflection.Assembly"
                    )
                {
                    switch (method.Reference.Name)
                    {
                    case "GetExecutingAssembly": {
                        var assembly = Method.DeclaringType.Module.Assembly;
                        var asmNode  = new JSAssembly(assembly);
                        ParentNode.ReplaceChild(ie, asmNode);
                        VisitReplacement(asmNode);

                        return;
                    }

                    case "GetType": {
                        switch (method.Method.Parameters.Length)
                        {
                        case 1:
                        case 2:
                            JSExpression throwOnFail = new JSBooleanLiteral(false);
                            if (method.Method.Parameters.Length == 2)
                            {
                                throwOnFail = ie.Arguments[1];
                            }

                            var invocation = JSIL.GetTypeFromAssembly(
                                ie.ThisReference, ie.Arguments[0], throwOnFail
                                );
                            ParentNode.ReplaceChild(ie, invocation);
                            VisitReplacement(invocation);

                            return;
                        }

                        break;
                    }
                    }
                }
                else if (
                    method.Method.DeclaringType.Definition.FullName == "System.Array" &&
                    (ie.Arguments.Count == 1)
                    )
                {
                    switch (method.Method.Name)
                    {
                    case "GetLength":
                    case "GetUpperBound": {
                        var index = ie.Arguments[0] as JSLiteral;
                        if (index != null)
                        {
                            var newDot = JSDotExpression.New(thisExpression, new JSStringIdentifier(
                                                                 String.Format("length{0}", Convert.ToInt32(index.Literal)),
                                                                 TypeSystem.Int32
                                                                 ));

                            if (method.Method.Name == "GetUpperBound")
                            {
                                var newExpr = new JSBinaryOperatorExpression(
                                    JSOperator.Subtract, newDot, JSLiteral.New(1), TypeSystem.Int32
                                    );
                                ParentNode.ReplaceChild(ie, newExpr);
                            }
                            else
                            {
                                ParentNode.ReplaceChild(ie, newDot);
                            }
                        }
                        break;
                    }

                    case "GetLowerBound":
                        ParentNode.ReplaceChild(ie, JSLiteral.New(0));
                        break;
                    }
                }
            }

            VisitChildren(ie);
        }
Exemple #17
0
        public JSExpression MaybeReplaceMethodCall(MethodReference caller, MethodReference method, MethodInfo methodInfo, JSExpression thisExpression, JSExpression[] arguments, TypeReference resultType, bool explicitThis)
        {
            var typeSystem = method.Module.TypeSystem;
            var fullName   = method.FullName;

            switch (fullName)
            {
            case "System.Double System.Math::Sqrt(System.Double)":
                return(new AbstractSExpression(
                           "f64.sqrt",
                           typeSystem.Double,
                           arguments,
                           isConstantIfArgumentsAre: true
                           ));

            case "System.Double System.Math::Floor(System.Double)":
                return(new AbstractSExpression(
                           "f64.floor",
                           typeSystem.Double,
                           arguments,
                           isConstantIfArgumentsAre: true
                           ));

            case "System.Double System.Math::Ceiling(System.Double)":
                return(new AbstractSExpression(
                           "f64.ceil",
                           typeSystem.Double,
                           arguments,
                           isConstantIfArgumentsAre: true
                           ));

            case "System.Void Wasm.Test::Printf(System.String,System.Object[])":
                // HACK: Ignored for now
                return(new JSNullExpression());

            case "System.Void Wasm.Test::Invoke(System.String,System.Object[])": {
                var literalName    = (JSStringLiteral)arguments[0];
                var argumentValues = UnpackArgsArray(arguments[1]);

                return(new InvokeExport(
                           literalName.Value, argumentValues
                           ));
            }

            case "System.Void Wasm.Test::AssertReturn(System.Object,System.String,System.Object[])": {
                var    expected = arguments[0];
                string methodName;
                if (!ExtractLiteral(arguments[1], out methodName))
                {
                    throw new Exception("Expected export name as arg1 of assertreturn");
                }
                var invokeArguments = UnpackArgsArray(arguments[2]);

                return(new AssertReturn(expected, methodName, invokeArguments));
            }

            case "System.Void Wasm.Heap::SetHeapSize(System.Int32)": {
                var td = caller.DeclaringType.Resolve();
                var hs = WasmUtil.HeapSizes;
                if (hs.ContainsKey(td))
                {
                    throw new Exception("Heap size for type " + td.FullName + " already set");
                }

                long heapSize;
                if (!ExtractLiteral(arguments[0], out heapSize))
                {
                    throw new ArgumentException("SetHeapSize's argument must be an int literal");
                }

                hs.Add(td, (int)heapSize);

                return(new JSNullExpression());
            }

            case "System.Int32 Wasm.HeapI32::get_Item(System.Int32)":
            case "System.Int32 Wasm.HeapI32::get_Item(System.Int32,System.Int32)": {
                JSExpression actualAddress;
                if (arguments.Length == 2)
                {
                    actualAddress = Add(typeSystem, arguments[0], arguments[1]);
                }
                else
                {
                    actualAddress = arguments[0];
                }

                // HACK: Indices are in elements, not bytes
                var actualAddressBytes = Mul(typeSystem, actualAddress, JSLiteral.New(4));

                return(new GetMemory(typeSystem.Int32, false, actualAddressBytes));
            }

            case "System.Byte Wasm.HeapU8::get_Item(System.Int32)":
            case "System.Byte Wasm.HeapU8::get_Item(System.Int32,System.Int32)": {
                JSExpression actualAddress;
                if (arguments.Length == 2)
                {
                    actualAddress = Add(typeSystem, arguments[0], arguments[1]);
                }
                else
                {
                    actualAddress = arguments[0];
                }

                return(new GetMemory(typeSystem.Byte, false, actualAddress));
            }

            case "System.Void Wasm.HeapI32::set_Item(System.Int32,System.Int32)":
            case "System.Void Wasm.HeapI32::set_Item(System.Int32,System.Int32,System.Int32)": {
                JSExpression actualAddress;
                if (arguments.Length == 3)
                {
                    actualAddress = Add(typeSystem, arguments[0], arguments[1]);
                }
                else
                {
                    actualAddress = arguments[0];
                }

                // HACK: Indices are in elements, not bytes
                var actualAddressBytes = Mul(typeSystem, actualAddress, JSLiteral.New(4));

                return(new SetMemory(typeSystem.Int32, false, actualAddressBytes, arguments[arguments.Length - 1]));
            }

            case "System.Void Wasm.HeapU8::set_Item(System.Int32,System.Byte)":
            case "System.Void Wasm.HeapU8::set_Item(System.Int32,System.Int32,System.Byte)": {
                JSExpression actualAddress;
                if (arguments.Length == 3)
                {
                    actualAddress = Add(typeSystem, arguments[0], arguments[1]);
                }
                else
                {
                    actualAddress = arguments[0];
                }

                return(new SetMemory(typeSystem.Byte, false, actualAddress, arguments[arguments.Length - 1]));
            }

            case "System.Char System.String::get_Chars(System.Int32)": {
                var actualAddress = Add(typeSystem, thisExpression, arguments[0]);
                return(new GetMemory(
                           typeSystem.Byte, false, actualAddress
                           ));
            }

            case "System.Int32 System.String::get_Length()": {
                return(new GetStringLength(thisExpression));
            }

            case "System.Int32* Wasm.HeapI32::get_Base()":
            case "System.Byte* Wasm.HeapU8::get_Base()": {
                return(JSLiteral.DefaultValue(method.ReturnType));
            }

            case "System.Void Wasm.Heap::SetStdout(System.String)": {
                // FIXME: Store the filename somewhere
                return(new JSNullExpression());
            }

            case "System.Void Wasm.Heap::Write(System.Int32,System.Int32)": {
                return(new StdoutWrite(arguments[0], arguments[1]));
            }
            }

            if (false)
            {
                Console.WriteLine("// Treating method '{0}' as runtime call", fullName);
            }

            return(null);
        }
        public void VisitNode(JSCastExpression ce)
        {
            var currentType = ce.Expression.GetActualType(TypeSystem);
            var targetType  = ce.NewType;

            JSExpression newExpression = null;
            var          innerCast     = ce.Expression as JSCastExpression;

            if (targetType.FullName == "System.ValueType")
            {
                var replacement = ce.Expression;
                ParentNode.ReplaceChild(ce, replacement);
                VisitReplacement(replacement);
                return;
            }
            else if (
                TypeUtil.IsIntegralOrEnum(currentType) &&
                (targetType.MetadataType == MetadataType.Char)
                )
            {
                newExpression = JSInvocationExpression.InvokeStatic(
                    JS.fromCharCode, new[] { ce.Expression }, true
                    );
            }
            else if (
                (currentType.MetadataType == MetadataType.Char) &&
                TypeUtil.IsIntegral(targetType)
                )
            {
                newExpression = JSInvocationExpression.InvokeMethod(
                    JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true
                    );
            }
            else if (
                IntroduceEnumCasts.IsEnumOrNullableEnum(currentType)
                )
            {
                TypeInfo enumInfo;
                var      isNullable = TypeUtil.IsNullable(currentType);

                if (isNullable)
                {
                    int temp;
                    var git = (GenericInstanceType)TypeUtil.FullyDereferenceType(currentType, out temp);
                    enumInfo = TypeInfo.Get(git.GenericArguments[0]);
                }
                else
                {
                    enumInfo = TypeInfo.Get(currentType);
                }

                if (enumInfo == null)
                {
                    throw new InvalidOperationException("Unable to extract enum type from typereference " + currentType);
                }

                if (targetType.MetadataType == MetadataType.Boolean)
                {
                    newExpression = new JSBinaryOperatorExpression(
                        JSOperator.NotEqual,
                        JSCastExpression.New(ce.Expression, TypeSystem.Int32, TypeSystem, true, true),
                        new JSIntegerLiteral(0, typeof(Int32)),
                        TypeSystem.Boolean
                        );
                }
                else if (TypeUtil.IsNumeric(targetType))
                {
                    if (isNullable)
                    {
                        newExpression = new JSNullableCastExpression(ce.Expression, new JSType(targetType));
                    }
                    else if (
                        ce.Expression is JSCastExpression &&
                        (((JSCastExpression)ce.Expression).Expression.GetActualType(TypeSystem).MetadataType == MetadataType.Int64 ||
                         ((JSCastExpression)ce.Expression).Expression.GetActualType(TypeSystem).MetadataType == MetadataType.UInt64)
                        )
                    {
                        newExpression = ce.Expression;
                    }
                    else
                    {
                        newExpression = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(targetType), ce.Expression, null, true
                            );
                    }
                }
                else if (targetType.FullName == "System.Enum")
                {
                    newExpression = ce.Expression;
                }
                else
                {
                    // Debugger.Break();
                }
            }
            else if (
                (targetType.MetadataType == MetadataType.Boolean) &&
                (ce.Expression is JSAsExpression) &&
                ((JSAsExpression)ce.Expression).GetActualType(TypeSystem) is GenericParameter
                )
            {
                // C# expressions such as (t is T) (where T is a generic parameter). See issue #150.
                // Tested with AsWithGenericParameter.cs
                newExpression = new JSBinaryOperatorExpression(
                    JSOperator.NotEqual,
                    ce.Expression, new JSNullLiteral(currentType),
                    TypeSystem.Boolean
                    );
            }
            else if (
                (targetType.MetadataType == MetadataType.Boolean) &&
                // A cast from Object to Boolean can occur in two forms:
                // An implied conversion, where an object expression is treated as a boolean (logicnot operation, etc).
                //  In this case, we want to do 'obj != null' to make it a boolean.
                // An explicit conversion, where an object expression is unboxed to boolean.
                //  In this case we want to leave it as-is.
                (ce.IsCoercion || (currentType.FullName != "System.Object"))
                )
            {
                newExpression = new JSBinaryOperatorExpression(
                    JSOperator.NotEqual,
                    ce.Expression, new JSDefaultValueLiteral(currentType),
                    TypeSystem.Boolean
                    );
            }
            else if (
                TypeUtil.IsNumeric(targetType) &&
                TypeUtil.IsNumeric(currentType) &&
                !TypeUtil.TypesAreEqual(targetType, currentType, true)
                )
            {
                TypeReference innerType = null;
                if (innerCast != null)
                {
                    innerType = innerCast.Expression.GetActualType(TypeSystem);
                }

                if (
                    TypeUtil.TypesAreAssignable(TypeInfo, targetType, innerType) &&
                    (
                        (TypeUtil.IsFloatingPoint(targetType) == TypeUtil.IsFloatingPoint(currentType)) &&
                        (TypeUtil.IsFloatingPoint(targetType) == TypeUtil.IsFloatingPoint(innerType))
                    ) &&
                    (TypeUtil.IsSigned(targetType) == TypeUtil.IsSigned(innerType)) &&
                    (TypeUtil.SizeOfType(targetType) <= TypeUtil.SizeOfType(currentType)) &&
                    (TypeUtil.SizeOfType(targetType) >= TypeUtil.SizeOfType(innerType))
                    )
                {
                    // HACK: Turn pointless conversions like '(int32)(int64)(1 + 2)' into '(1 + 2)'
                    newExpression = innerCast.Expression;
                }
                else if (currentType.MetadataType == MetadataType.Int64)
                {
                    if (!EmulateInt64)
                    {
                        newExpression = ce;
                    }
                    else if (targetType.MetadataType == MetadataType.UInt64)
                    {
                        newExpression = JSInvocationExpression
                                        .InvokeMethod(
                            TypeSystem.Int64,
                            new JSFakeMethod("ToUInt64", TypeSystem.UInt64, new TypeReference[] { }, MethodTypeFactory),
                            ce.Expression);
                    }
                    else
                    {
                        newExpression = JSInvocationExpression
                                        .InvokeMethod(
                            TypeSystem.Int64,
                            new JSFakeMethod("ToNumber", targetType, new TypeReference[] { TypeSystem.Double, TypeSystem.Boolean }, MethodTypeFactory),
                            ce.Expression,
                            GetInt64ConversionArgs(targetType));
                    }
                }
                else if (currentType.MetadataType == MetadataType.UInt64)
                {
                    if (!EmulateInt64)
                    {
                        newExpression = ce;
                    }
                    else if (targetType.MetadataType == MetadataType.Int64)
                    {
                        newExpression = JSInvocationExpression
                                        .InvokeMethod(
                            TypeSystem.Int64,
                            new JSFakeMethod("ToInt64", TypeSystem.Int64, new TypeReference[] { }, MethodTypeFactory),
                            ce.Expression);
                    }
                    else
                    {
                        newExpression = JSInvocationExpression
                                        .InvokeMethod(
                            TypeSystem.Int64,
                            new JSFakeMethod("ToNumber", targetType, new TypeReference[] { TypeSystem.Double, TypeSystem.Boolean }, MethodTypeFactory),
                            ce.Expression,
                            GetInt64ConversionArgs(targetType));
                    }
                }
                else if (targetType.MetadataType == MetadataType.Int64)
                {
                    if (!EmulateInt64)
                    {
                        newExpression = ce;
                    }
                    else
                    {
                        newExpression = JSInvocationExpression.InvokeStatic(
                            new JSType(TypeSystem.Int64),
                            new JSFakeMethod("FromNumber", TypeSystem.Int64, new[] { currentType }, MethodTypeFactory),
                            new[] { ce.Expression }, true
                            );
                    }
                }
                else if (targetType.MetadataType == MetadataType.UInt64)
                {
                    if (!EmulateInt64)
                    {
                        newExpression = ce;
                    }
                    else
                    {
                        newExpression = JSInvocationExpression.InvokeStatic(
                            new JSType(TypeSystem.UInt64),
                            new JSFakeMethod("FromNumber", TypeSystem.UInt64, new[] { currentType }, MethodTypeFactory),
                            new[] { ce.Expression }, true
                            );
                    }
                }
                else if (TypeUtil.IsIntegral(currentType))
                {
                    if (!TypeUtil.IsIntegral(targetType))
                    {
                        // Integer -> float conversion
                        newExpression = new JSIntegerToFloatExpression(ce.Expression, targetType);
                    }
                    else if (TypeUtil.SizeOfType(currentType) < TypeUtil.SizeOfType(targetType))
                    {
                        // Widening integer -> integer conversion
                        newExpression = ce.Expression;
                    }
                    else
                    {
                        newExpression = null;
                    }
                }
                else if (TypeUtil.IsIntegral(targetType))
                {
                    newExpression = new JSTruncateExpression(ce.Expression);
                }
                else if (TypeUtil.SizeOfType(targetType) < TypeUtil.SizeOfType(currentType))
                {
                    // Narrowing double -> float conversion
                    newExpression = new JSDoubleToFloatExpression(ce.Expression);
                }
                else
                {
                    // Widening float -> double conversion
                    newExpression = new JSFloatToDoubleExpression(ce.Expression);
                }
            }
            else
            {
                // newExpression = JSIL.Cast(ce.Expression, targetType);
            }

            if ((newExpression != null) && (newExpression != ce))
            {
                ParentNode.ReplaceChild(ce, newExpression);
                VisitReplacement(newExpression);
            }
            else
            {
                // Debugger.Break();
                VisitChildren(ce);
            }
        }
Exemple #19
0
        public void VisitNode(JSCastExpression ce)
        {
            var currentType = ce.Expression.GetActualType(TypeSystem);
            var targetType  = ce.NewType;

            JSExpression newExpression = null;

            if (targetType.FullName == "System.ValueType")
            {
                var replacement = ce.Expression;
                ParentNode.ReplaceChild(ce, replacement);
                VisitReplacement(replacement);
                return;
            }
            else if (targetType.MetadataType == MetadataType.Char)
            {
                newExpression = JSInvocationExpression.InvokeStatic(
                    JS.fromCharCode, new[] { ce.Expression }, true
                    );
            }
            else if (
                (currentType.MetadataType == MetadataType.Char) &&
                TypeUtil.IsIntegral(targetType)
                )
            {
                newExpression = JSInvocationExpression.InvokeMethod(
                    JS.charCodeAt, ce.Expression, new[] { JSLiteral.New(0) }, true
                    );
            }
            else if (
                IntroduceEnumCasts.IsEnumOrNullableEnum(currentType)
                )
            {
                var enumInfo   = TypeInfo.Get(currentType);
                var isNullable = TypeUtil.IsNullable(currentType);

                if (targetType.MetadataType == MetadataType.Boolean)
                {
                    EnumMemberInfo enumMember;
                    if (enumInfo.ValueToEnumMember.TryGetValue(0, out enumMember))
                    {
                        newExpression = new JSBinaryOperatorExpression(
                            JSOperator.NotEqual, ce.Expression,
                            new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean
                            );
                    }
                    else if (enumInfo.ValueToEnumMember.TryGetValue(1, out enumMember))
                    {
                        newExpression = new JSBinaryOperatorExpression(
                            JSOperator.Equal, ce.Expression,
                            new JSEnumLiteral(enumMember.Value, enumMember), TypeSystem.Boolean
                            );
                    }
                    else
                    {
                        newExpression = new JSUntranslatableExpression(String.Format(
                                                                           "Could not cast enum of type '{0}' to boolean because it has no zero value or one value",
                                                                           currentType.FullName
                                                                           ));
                    }
                }
                else if (TypeUtil.IsNumeric(targetType))
                {
                    if (isNullable)
                    {
                        newExpression = JSIL.ValueOfNullable(
                            ce.Expression
                            );
                    }
                    else
                    {
                        newExpression = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(targetType), ce.Expression, null, true
                            );
                    }
                }
                else if (targetType.FullName == "System.Enum")
                {
                    newExpression = ce.Expression;
                }
                else
                {
                    // Debugger.Break();
                }
            }
            else if (
                (targetType.MetadataType == MetadataType.Boolean) &&
                // A cast from Object to Boolean can occur in two forms:
                // An implied conversion, where an object expression is treated as a boolean (logicnot operation, etc).
                //  In this case, we want to do 'obj != null' to make it a boolean.
                // An explicit conversion, where an object expression is unboxed to boolean.
                //  In this case we want to leave it as-is.
                (ce.IsCoercion || (currentType.FullName != "System.Object"))
                )
            {
                newExpression = new JSBinaryOperatorExpression(
                    JSBinaryOperator.NotEqual,
                    ce.Expression, new JSDefaultValueLiteral(currentType),
                    TypeSystem.Boolean
                    );
            }
            else if (
                TypeUtil.IsNumeric(targetType) &&
                TypeUtil.IsNumeric(currentType)
                )
            {
                if (
                    TypeUtil.IsIntegral(currentType) ||
                    !TypeUtil.IsIntegral(targetType)
                    )
                {
                    newExpression = ce.Expression;
                }
                else
                {
                    newExpression = new JSTruncateExpression(ce.Expression);
                }
            }
            else
            {
                // newExpression = JSIL.Cast(ce.Expression, targetType);
            }

            if (newExpression != null)
            {
                ParentNode.ReplaceChild(ce, newExpression);
                VisitReplacement(newExpression);
            }
            else
            {
                // Debugger.Break();
                VisitChildren(ce);
            }
        }
Exemple #20
0
        public void VisitNode(JSInvocationExpression ie)
        {
            var type           = ie.JSType;
            var method         = ie.JSMethod;
            var thisExpression = ie.ThisReference;

            if (method != null)
            {
                if (
                    (type != null) &&
                    (type.Type.FullName == "System.Object")
                    )
                {
                    switch (method.Method.Member.Name)
                    {
                    case ".ctor": {
                        var replacement = new JSNullExpression();
                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }

                    case "ReferenceEquals": {
                        var lhs = ie.Arguments[0];
                        var rhs = ie.Arguments[1];

                        var lhsType = lhs.GetActualType(TypeSystem);
                        var rhsType = rhs.GetActualType(TypeSystem);

                        JSNode replacement;

                        // Structs can never compare equal with ReferenceEquals
                        if (TypeUtil.IsStruct(lhsType) || TypeUtil.IsStruct(rhsType))
                        {
                            replacement = JSLiteral.New(false);
                        }
                        else
                        {
                            replacement = new JSBinaryOperatorExpression(
                                JSOperator.Equal,
                                lhs, rhs,
                                TypeSystem.Boolean
                                );
                        }

                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }

                    case "GetType": {
                        JSNode replacement;

                        var thisType = JSExpression.DeReferenceType(thisExpression.GetActualType(TypeSystem), false);
                        if ((thisType is GenericInstanceType) && thisType.FullName.StartsWith("System.Nullable"))
                        {
                            var git = (GenericInstanceType)thisType;

                            replacement = new JSTernaryOperatorExpression(
                                new JSBinaryOperatorExpression(
                                    JSOperator.NotEqual,
                                    thisExpression, new JSNullLiteral(thisType),
                                    TypeSystem.Boolean
                                    ),
                                new JSTypeOfExpression(git.GenericArguments[0]),
                                JSIL.ThrowNullReferenceException(),
                                new TypeReference("System", "Type", TypeSystem.Object.Module, TypeSystem.Object.Scope, false)
                                );
                        }
                        else
                        {
                            replacement = JSIL.GetTypeOf(thisExpression);
                        }

                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }
                    }
                }
                else if (
                    (type != null) &&
                    (type.Type.FullName == "System.ValueType")
                    )
                {
                    switch (method.Method.Member.Name)
                    {
                    case "Equals": {
                        var replacement = JSIL.StructEquals(ie.ThisReference, ie.Arguments.First());
                        ParentNode.ReplaceChild(ie, replacement);
                        VisitReplacement(replacement);

                        return;
                    }
                    }
                }
                else if (
                    (type != null) &&
                    IsNullable(type.Type)
                    )
                {
                    var t        = (type.Type as GenericInstanceType).GenericArguments[0];
                    var @null    = JSLiteral.Null(t);
                    var @default = new JSDefaultValueLiteral(t);

                    switch (method.Method.Member.Name)
                    {
                    case ".ctor":
                        JSExpression value;
                        if (ie.Arguments.Count == 0)
                        {
                            value = @null;
                        }
                        else
                        {
                            value = ie.Arguments[0];
                        }

                        var boe = new JSBinaryOperatorExpression(
                            JSOperator.Assignment, ie.ThisReference, value, type.Type
                            );
                        ParentNode.ReplaceChild(ie, boe);
                        VisitReplacement(boe);

                        break;

                    case "GetValueOrDefault": {
                        var replacement = JSIL.ValueOfNullableOrDefault(
                            ie.ThisReference,
                            (ie.Arguments.Count == 0)
                                    ? @default
                                    : ie.Arguments[0]
                            );

                        if (ParentNode is JSResultReferenceExpression)
                        {
                            // HACK: Replacing the invocation inside a result reference is incorrect, so we need to walk up the stack
                            //  and replace the result reference with the ternary instead.
                            _ResultReferenceReplacement = replacement;
                        }
                        else
                        {
                            ParentNode.ReplaceChild(ie, replacement);
                            VisitReplacement(replacement);
                        }

                        break;
                    }

                    case "get_HasValue": {
                        var replacement = JSIL.NullableHasValue(ie.ThisReference);
                        if (ParentNode is JSResultReferenceExpression)
                        {
                            _ResultReferenceReplacement = replacement;
                        }
                        else
                        {
                            ParentNode.ReplaceChild(ie, replacement);
                            VisitReplacement(replacement);
                        }

                        break;
                    }

                    case "get_Value": {
                        var replacement = JSIL.ValueOfNullable(ie.ThisReference);
                        if (ParentNode is JSResultReferenceExpression)
                        {
                            _ResultReferenceReplacement = replacement;
                        }
                        else
                        {
                            ParentNode.ReplaceChild(ie, replacement);
                            VisitReplacement(replacement);
                        }

                        break;
                    }

                    case "Equals":
                        JSBinaryOperatorExpression equality = new JSBinaryOperatorExpression(JSOperator.Equal, ie.ThisReference, ie.Parameters.First().Value, type.Type);
                        ParentNode.ReplaceChild(ie, equality);
                        VisitReplacement(equality);
                        break;

                    default:
                        throw new NotImplementedException(method.Method.Member.FullName);
                    }

                    return;
                }
                else if (
                    (type != null) &&
                    TypeUtil.TypesAreEqual(TypeSystem.String, type.Type) &&
                    (method.Method.Name == "Concat")
                    )
                {
                    if (ie.Arguments.Count > 2)
                    {
                        if (ie.Arguments.All(
                                (arg) => TypeUtil.TypesAreEqual(
                                    TypeSystem.String, arg.GetActualType(TypeSystem)
                                    )
                                ))
                        {
                            var boe = JSBinaryOperatorExpression.New(
                                JSOperator.Add,
                                ie.Arguments,
                                TypeSystem.String
                                );

                            ParentNode.ReplaceChild(
                                ie,
                                boe
                                );

                            VisitReplacement(boe);
                        }
                    }
                    else if (
                        // HACK: Fix for #239, only convert concat call into + if both sides are non-null literals
                        (ie.Arguments.Count == 2)
                        )
                    {
                        var lhs = ie.Arguments[0];
                        var rhs = ie.Arguments[1];

                        var isAddOk = (lhs is JSStringLiteral) && (rhs is JSStringLiteral);

                        var lhsType = TypeUtil.DereferenceType(lhs.GetActualType(TypeSystem));
                        if (!(
                                TypeUtil.TypesAreEqual(TypeSystem.String, lhsType) ||
                                TypeUtil.TypesAreEqual(TypeSystem.Char, lhsType)
                                ))
                        {
                            lhs     = JSInvocationExpression.InvokeMethod(lhsType, JS.toString, lhs, null);
                            isAddOk = true;
                        }

                        var rhsType = TypeUtil.DereferenceType(rhs.GetActualType(TypeSystem));
                        if (!(
                                TypeUtil.TypesAreEqual(TypeSystem.String, rhsType) ||
                                TypeUtil.TypesAreEqual(TypeSystem.Char, rhsType)
                                ))
                        {
                            rhs     = JSInvocationExpression.InvokeMethod(rhsType, JS.toString, rhs, null);
                            isAddOk = true;
                        }

                        if (isAddOk)
                        {
                            var boe = new JSBinaryOperatorExpression(
                                JSOperator.Add, lhs, rhs, TypeSystem.String
                                );

                            ParentNode.ReplaceChild(
                                ie, boe
                                );

                            VisitReplacement(boe);
                        }
                    }
                    else if (
                        TypeUtil.GetTypeDefinition(ie.Arguments[0].GetActualType(TypeSystem)).FullName == "System.Array"
                        )
                    {
                    }
                    else
                    {
                        var firstArg = ie.Arguments.FirstOrDefault();

                        ParentNode.ReplaceChild(
                            ie, firstArg
                            );

                        if (firstArg != null)
                        {
                            VisitReplacement(firstArg);
                        }
                    }
                    return;
                }
                else if (
                    TypeUtil.IsDelegateType(method.Reference.DeclaringType) &&
                    (method.Method.Name == "Invoke")
                    )
                {
                    var newIe = new JSDelegateInvocationExpression(
                        thisExpression, ie.GetActualType(TypeSystem), ie.Arguments.ToArray()
                        );
                    ParentNode.ReplaceChild(ie, newIe);

                    VisitReplacement(newIe);
                    return;
                }
                else if (
                    (method.Reference.DeclaringType.Name == "RuntimeHelpers") &&
                    (method.Method.Name == "InitializeArray")
                    )
                {
                    var array       = ie.Arguments[0];
                    var arrayType   = array.GetActualType(TypeSystem);
                    var field       = ie.Arguments[1].SelfAndChildrenRecursive.OfType <JSField>().First();
                    var initializer = JSArrayExpression.UnpackArrayInitializer(arrayType, field.Field.Member.InitialValue);

                    var copy = JSIL.ShallowCopy(array, initializer, arrayType);
                    ParentNode.ReplaceChild(ie, copy);
                    VisitReplacement(copy);
                    return;
                }
                else if (
                    method.Reference.DeclaringType.FullName == "System.Reflection.Assembly"
                    )
                {
                    switch (method.Reference.Name)
                    {
                    case "GetExecutingAssembly": {
                        var assembly = Method.DeclaringType.Module.Assembly;
                        var asmNode  = new JSReflectionAssembly(assembly);
                        ParentNode.ReplaceChild(ie, asmNode);
                        VisitReplacement(asmNode);

                        return;
                    }
                    }
                }
                else if (
                    method.Method.DeclaringType.Definition.FullName == "System.Array" &&
                    (ie.Arguments.Count == 1)
                    )
                {
                    switch (method.Method.Name)
                    {
                    case "GetLength":
                    case "GetUpperBound": {
                        var index = ie.Arguments[0] as JSLiteral;
                        if (index != null)
                        {
                            var newDot = JSDotExpression.New(thisExpression, new JSStringIdentifier(
                                                                 String.Format("length{0}", Convert.ToInt32(index.Literal)),
                                                                 TypeSystem.Int32
                                                                 ));

                            if (method.Method.Name == "GetUpperBound")
                            {
                                var newExpr = new JSBinaryOperatorExpression(
                                    JSOperator.Subtract, newDot, JSLiteral.New(1), TypeSystem.Int32
                                    );
                                ParentNode.ReplaceChild(ie, newExpr);
                            }
                            else
                            {
                                ParentNode.ReplaceChild(ie, newDot);
                            }
                        }
                        break;
                    }

                    case "GetLowerBound":
                        ParentNode.ReplaceChild(ie, JSLiteral.New(0));
                        break;
                    }
                }
            }

            VisitChildren(ie);
        }
Exemple #21
0
        void EmitCast(JSExpression value, TypeReference toType)
        {
            var fromType = value.GetActualType(TypeSystem);

            var fromIntegral = TypeUtil.IsIntegral(fromType);
            var toIntegral   = TypeUtil.IsIntegral(toType);

            var fromSize = WasmUtil.SizeOfType(fromType);
            var toSize   = WasmUtil.SizeOfType(toType);

            var fromSign = TypeUtil.IsSigned(fromType);
            var toSign   = TypeUtil.IsSigned(toType);

            var signSuffix = fromSign.GetValueOrDefault(toSign.GetValueOrDefault(true))
                ? "s"
                : "u";

            if (fromIntegral && toIntegral)
            {
                if ((toSize == 4) && (fromSize == 8))
                {
                    Formatter.WriteRaw("(i32.wrap/i64 ");
                    Visit(value);
                    Formatter.WriteRaw(")");
                    return;
                }
                else if ((toSize == 8) && (fromSize == 4))
                {
                    Formatter.WriteRaw("(i64.extend_{0}/i32 ", signSuffix);
                    Visit(value);
                    Formatter.WriteRaw(")");
                    return;
                }
                else if ((toSize == fromSize) && (toSign != fromSign))
                {
                    Visit(value);
                    return;
                }
                else if ((toSize == 2) || (toSize == 1))
                {
                    var mask        = (1 << (8 * toSize)) - 1;
                    var synthesized = new JSBinaryOperatorExpression(
                        JSOperator.BitwiseAnd,
                        value, JSLiteral.New(mask),
                        toType
                        );
                    Visit(synthesized);
                    return;
                }
                else if (toType.FullName == "JSIL.Types.NativeInt")
                {
                    Visit(value);
                    return;
                }
            }
            else if (toIntegral)
            {
                Formatter.WriteRaw(
                    "({0}.trunc_{1}/{2} ",
                    WasmUtil.PickTypeKeyword(toType),
                    signSuffix,
                    WasmUtil.PickTypeKeyword(fromType)
                    );
                Visit(value);
                Formatter.WriteRaw(")");
                return;
            }

            Console.Error.WriteLine("unimplemented cast {0} -> {1}", fromType, toType);
            Visit(value);
        }