예제 #1
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);
        }