public void VisitNode(JSLiteral literal) { var literalType = literal.GetActualType(TypeSystem); var typeToken = WasmUtil.PickTypeKeyword(literalType); if (typeToken == null) { Console.WriteLine("AstEmitter Unhandled literal type {0}", literalType.FullName); Formatter.WriteSExpr("untranslatable.literal"); } dynamic literalValue; if (literal is JSDefaultValueLiteral) { literalValue = 0; } else { literalValue = (dynamic)literal.Literal; if (literalValue is bool) { literalValue = (literalValue ? 1 : 0); } } Formatter.WriteSExpr( "const." + typeToken, // HACK (_) => Formatter.Value(literalValue) ); }
private void VisitLiteral(JSLiteral literal, TypeReference forcedType = null) { var literalType = forcedType ?? literal.GetActualType(TypeSystem); if ((literal is JSNullLiteral) && (literalType.FullName == "System.Object")) { // HACK: ILSpy screws up the type inference... VisitStringLiteral(null); return; } var typeToken = WasmUtil.PickTypeKeyword(literalType); if (typeToken == null) { Console.WriteLine("AstEmitter Unhandled literal type {0}", literalType.FullName); Formatter.WriteSExpr("untranslatable.literal"); } if (literalType.FullName == "System.String") { if ((literal is JSDefaultValueLiteral) || (literal is JSNullLiteral)) { VisitStringLiteral(null); } else { var literalStr = (string)literal.Literal; VisitStringLiteral(literalStr); } return; } dynamic literalValue; if (literal is JSDefaultValueLiteral) { literalValue = 0; } else { literalValue = (dynamic)literal.Literal; if (literalValue is bool) { literalValue = (literalValue ? 1 : 0); } else if (literalValue is char) { literalValue = (int)(char)literalValue; } } Formatter.WriteSExpr( typeToken + ".const", // HACK (_) => Formatter.Value(literalValue) ); }
public void VisitNode(JSBinaryOperatorExpression boe) { var boeType = boe.GetActualType(TypeSystem); var typeToken = WasmUtil.PickTypeKeyword(boeType); if (typeToken == null) { Console.WriteLine("Unhandled binary operator type {0}", boeType); return; } if (boe.Operator == JSOperator.Assignment) { Assign(boe.Left, boe.Right); return; } string keyword; if (!OperatorTable.TryGetValue(boe.Operator, out keyword)) { Console.WriteLine("Unimplemented operator {0}", boe.Operator); return; } var leftType = boe.Left.GetActualType(TypeSystem); var rightType = boe.Right.GetActualType(TypeSystem); var leftSign = TypeUtil.IsSigned(leftType); // HACK: Emit the argument type since we're comparing it if (boe.Operator is JSComparisonOperator) { typeToken = WasmUtil.PickTypeKeyword(leftType); } var signSuffix = ""; if (leftSign.HasValue && TypeUtil.IsIntegral(leftType)) { signSuffix = leftSign.Value ? "s" : "u"; } var actualKeyword = string.Format( keyword + "." + typeToken, signSuffix ); Formatter.WriteSExpr( actualKeyword, (_) => EmitArgumentList(_, new[] { boe.Left, boe.Right }, true), true, false ); }
public void EmitField(DecompilerContext context, IAstEmitter astEmitter, FieldDefinition field, JSRawOutputIdentifier dollar, JSExpression defaultValue) { var fieldInfo = Translator.TypeInfoProvider.GetField(field); var typeKeyword = WasmUtil.PickTypeKeyword(fieldInfo.FieldType); // Unhandled type if (typeKeyword == null) { return; } GetFieldOffset(field); }
public void VisitNode(JSIntegerToFloatExpression itfe) { var type = itfe.GetActualType(TypeSystem); var typeToken = WasmUtil.PickTypeKeyword(type); var originalType = itfe.Expression.GetActualType(TypeSystem); var originalTypeToken = WasmUtil.PickTypeKeyword(originalType); Formatter.WriteSExpr( "converts." + originalTypeToken + "." + typeToken, (_) => { Visit(itfe.Expression); } ); }
public void EmitField(DecompilerContext context, IAstEmitter astEmitter, FieldDefinition field, JSRawOutputIdentifier dollar, JSExpression defaultValue) { var fieldInfo = Translator.TypeInfoProvider.GetField(field); var typeKeyword = WasmUtil.PickTypeKeyword(fieldInfo.FieldType); // Unhandled type if (typeKeyword == null) { return; } Switch(PrecedingType.Global); Formatter.WriteRaw("(global ${0} {1})", WasmUtil.EscapeIdentifier(fieldInfo.Name), typeKeyword); Formatter.ConditionalNewLine(); }
public void VisitNode(JSIntegerToFloatExpression itfe) { var type = itfe.GetActualType(TypeSystem); var typeToken = WasmUtil.PickTypeKeyword(type); var originalType = itfe.Expression.GetActualType(TypeSystem); var originalTypeToken = WasmUtil.PickTypeKeyword(originalType); Formatter.WriteSExpr( string.Format( "{0}.convert_s/{1}", typeToken, originalTypeToken ), (_) => { Visit(itfe.Expression); } ); }
public static Tuple <bool, string> ShouldSkipMember(MemberReference member) { var fr = member as FieldReference; var mr = member as MethodReference; if (fr != null) { return(Skip(WasmUtil.PickTypeKeyword(fr.FieldType) == null, "Unsupported field type")); } if (mr != null) { return(Skip(WasmUtil.PickTypeKeyword(mr.ReturnType) == null, "Unsupported return type")); } return(Skip(false)); }
public GetMemory( TypeReference type, bool isAligned, JSExpression addressInBytes ) : base( string.Format( "{0}.load{1}{2}", WasmUtil.PickTypeKeyword(type), WasmUtil.PickMemoryTypeSuffix(type, false), isAligned ? "" : "/1" ), addressInBytes ) { Type = type; IsAligned = isAligned; }
public SetMemory( TypeReference type, bool isAligned, JSExpression addressInBytes, JSExpression value ) : base( string.Format( "{0}.store{1}{2}", WasmUtil.PickTypeKeyword(type), WasmUtil.PickMemoryTypeSuffix(type, true), isAligned ? "" : "/1" ), addressInBytes, value ) { Type = type; IsAligned = isAligned; LineBreakInside = true; LineBreakAfter = true; }
public void EmitFunctionBody(IAstEmitter astEmitter, MethodDefinition method, JSFunctionExpression function) { // Skip Main() and emit it at the footer if (Assembly.EntryPoint == method) { // HACK: Store this so we can use it to emit the entry point's body later EntryPointAstEmitter = astEmitter; return; } var name = WasmUtil.FormatMemberName(method); Switch(PrecedingType.Function, true); Formatter.WriteRaw("(func ${0}", name); Formatter.Indent(); Formatter.NewLine(); int v = 0; foreach (var kvp in function.AllVariables) { var variable = kvp.Value; var type = WasmUtil.PickTypeKeyword(variable.IdentifierType); if (type != null) { Formatter.WriteRaw( "({0} ${1} {2}) ", variable.IsParameter ? "param" : "local", WasmUtil.EscapeIdentifier(kvp.Key), type ); if (v++ >= 3) { v = 0; Formatter.NewLine(); } } } if (function.LabelGroupCount > 0) { Formatter.NewLine(); } for (var i = 0; i < function.LabelGroupCount; i++) { Formatter.WriteRaw("(local $currentLabel_{0} i32) ", i); } var returnType = WasmUtil.PickTypeKeyword(method.ReturnType); if (returnType != "void") { Formatter.NewLine(); Formatter.WriteRaw("(result {0})", returnType); } Formatter.ConditionalNewLine(); Formatter.NewLine(); astEmitter.Emit(function.Body); Formatter.ConditionalNewLine(); Formatter.Unindent(); Formatter.WriteRaw(")"); Formatter.NewLine(); }
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(); }
public void VisitNode(JSBinaryOperatorExpression boe) { var boeType = boe.GetActualType(TypeSystem); var typeToken = WasmUtil.PickTypeKeyword(boeType); if (boe.Operator == JSOperator.Assignment) { Assign(boe.Left, boe.Right); return; } string keyword; if (!OperatorTable.TryGetValue(boe.Operator, out keyword)) { Console.WriteLine("Unimplemented operator {0}", boe.Operator); return; } var leftType = boe.Left.GetActualType(TypeSystem); var rightType = boe.Right.GetActualType(TypeSystem); var leftSign = TypeUtil.IsSigned(leftType); // HACK: Emit the argument type since we're comparing it if (boe.Operator is JSComparisonOperator) { typeToken = WasmUtil.PickTypeKeyword(leftType); } var signSuffix = ""; if ( (leftSign.HasValue && TypeUtil.IsIntegral(leftType)) || // HACK (leftType.FullName == "System.Char") ) { signSuffix = leftSign.GetValueOrDefault(true) ? "_s" : "_u"; } else if ( TypeUtil.IsPointer(leftType) || TypeUtil.IsPointer(rightType) ) { signSuffix = "_u"; } var actualKeyword = string.Format( typeToken + "." + keyword, signSuffix ); // HACK: wasm i64 shift takes i64 shift amount var right = boe.Right; if ( (boe.Operator == JSOperator.ShiftLeft) || (boe.Operator == JSOperator.ShiftRight) ) { right = JSChangeTypeExpression.New(right, leftType, TypeSystem); } if (typeToken == null) { Console.WriteLine("Unhandled binary operator type {0} ({1})", boeType, boe); return; } Formatter.WriteSExpr( actualKeyword, (_) => EmitArgumentList(_, new[] { boe.Left, right }, true), true, false ); }
public void VisitNode(JSUnaryOperatorExpression uoe) { var resultType = uoe.GetActualType(TypeSystem); var typeToken = WasmUtil.PickTypeKeyword(resultType); if (typeToken == null) { Console.WriteLine("Unhandled unary operator type {0}", resultType); return; } if (uoe.Operator == JSOperator.LogicalNot) { Formatter.WriteRaw("({0}.xor ", typeToken); Visit(uoe.Expression); Formatter.WriteRaw(" ({0}.const 1))", typeToken); return; } else if (uoe.Operator == JSOperator.Negation) { Formatter.WriteRaw("({0}.sub ({0}.const 0) ", typeToken); Visit(uoe.Expression); Formatter.WriteRaw(")", typeToken); return; } string keyword; if (!OperatorTable.TryGetValue(uoe.Operator, out keyword)) { Console.WriteLine("Unimplemented operator {0}", uoe.Operator); return; } var operandType = uoe.Expression.GetActualType(TypeSystem); var sign = TypeUtil.IsSigned(operandType); var signSuffix = ""; if ( (sign.HasValue && TypeUtil.IsIntegral(operandType)) || // HACK (operandType.FullName == "System.Char") ) { signSuffix = sign.GetValueOrDefault(true) ? "_s" : "_u"; } var actualKeyword = string.Format( typeToken + "." + keyword, signSuffix ); Formatter.WriteSExpr( actualKeyword, (_) => EmitArgumentList(_, new[] { uoe.Expression }, true), true, false ); }
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); }