Skip to content

Commit

Permalink
Allow attributing a function to specify that its return value is a pa…
Browse files Browse the repository at this point in the history
…cked array.

Safety check return statements within functions to ensure that packed arrays are not returned as normal arrays or vice versa.
  • Loading branch information
kg committed Mar 23, 2013
1 parent df09acc commit ecdac93
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 6 deletions.
16 changes: 10 additions & 6 deletions JSIL/ILBlockTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ protected JSExpression Translate_ConstructorReplacement (
return newExpression;
}

protected JSExpression Translate_MethodReplacement (
protected JSExpression DoMethodReplacement (
JSMethod method, JSExpression thisExpression,
JSExpression[] arguments, bool @virtual, bool @static, bool explicitThis
) {
Expand Down Expand Up @@ -582,6 +582,8 @@ protected JSExpression Translate_MethodReplacement (
result = JSInvocationExpression.InvokeMethod(method.Reference.DeclaringType, method, thisExpression, arguments);
}

result = PackedArrayUtil.FilterInvocationResult(method.Method, result, TypeSystem);

return result;
}

Expand Down Expand Up @@ -1722,9 +1724,11 @@ protected JSContinueExpression Translate_LoopContinue (ILExpression node) {

protected JSReturnExpression Translate_Ret (ILExpression node) {
if (node.Arguments.FirstOrDefault() != null) {
return new JSReturnExpression(
TranslateNode(node.Arguments[0])
);
var returnValue = TranslateNode(node.Arguments[0]);

PackedArrayUtil.CheckReturnValue(TypeInfo.Get(ThisMethodReference) as Internal.MethodInfo, returnValue, TypeSystem);

return new JSReturnExpression(returnValue);
} else if (node.Arguments.Count == 0) {
return new JSReturnExpression();
} else {
Expand Down Expand Up @@ -2905,7 +2909,7 @@ protected JSExpression Translate_Call (ILExpression node, MethodReference method
thisExpression = new JSNullExpression();
}

var result = Translate_MethodReplacement(
var result = DoMethodReplacement(
new JSMethod(method, methodInfo, MethodTypes),
thisExpression, arguments, false,
!method.HasThis, explicitThis || methodInfo.IsConstructor
Expand Down Expand Up @@ -2975,7 +2979,7 @@ protected JSExpression Translate_Callvirt (ILExpression node, MethodReference me
);
}

var result = Translate_MethodReplacement(
var result = DoMethodReplacement(
new JSMethod(method, methodInfo, MethodTypes),
thisExpression, translatedArguments, true,
false, explicitThis
Expand Down
38 changes: 38 additions & 0 deletions JSIL/PackedStructArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,43 @@ public static string[] GetPackedArrayArgumentNames (MethodInfo method, out TypeR

return null;
}

public static JSExpression FilterInvocationResult (MethodInfo method, JSExpression result, TypeSystem typeSystem) {
if (method == null)
return result;

var resultType = result.GetActualType(typeSystem);
var resultIsPackedArray = PackedArrayUtil.IsPackedArrayType(resultType);
var returnValueAttribute = method.Metadata.GetAttribute("JSIL.Meta.JSPackedArrayReturnValueAttribute");

if (returnValueAttribute != null) {
if (!resultIsPackedArray)
return JSChangeTypeExpression.New(result, PackedArrayUtil.MakePackedArrayType(resultType, returnValueAttribute.Entries.First().Type), typeSystem);
}

return result;
}

public static void CheckReturnValue (MethodInfo method, JSExpression returnValue, TypeSystem typeSystem) {
if (method == null)
return;

var resultType = returnValue.GetActualType(typeSystem);
var resultIsPackedArray = PackedArrayUtil.IsPackedArrayType(resultType);

var returnValueAttribute = method.Metadata.GetAttribute("JSIL.Meta.JSPackedArrayReturnValueAttribute");
if (returnValueAttribute != null) {
if (!resultIsPackedArray)
throw new ArgumentException(
"Return value of method '" + method.Name + "' must be a packed array."
);
} else {
if (resultIsPackedArray)
throw new ArgumentException(
"Return value of method '" + method.Name + "' is a packed array. " +
"For this to be valid you must attach a JSPackedArrayReturnValueAttribute to the method."
);
}
}
}
}
8 changes: 8 additions & 0 deletions Meta/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@ public JSPackedArrayArgumentsAttribute (params string[] argumentNames) {
}
}

/// <summary>
/// Specifies that JSIL should represent the function's return value as a packed array.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
[JSIL.Runtime.LinkedType(typeof(JSIL.Runtime.IPackedArray<>))]
public class JSPackedArrayReturnValueAttribute : Attribute {
}

[AttributeUsage(AttributeTargets.Method)]
public class JSAllowPackedArrayArgumentsAttribute : Attribute {
}
Expand Down
27 changes: 27 additions & 0 deletions Tests/FailingTestCases/ReturnNormalArrayAsPackedArray.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using JSIL.Meta;

public struct IntFloatPair {
public int Int;
public float Float;

public override string ToString () {
return String.Format("Int={0:0000}, Float={1:000.000}", Int, Float);
}
}

public static class Program {
public static IntFloatPair[] PackedArray = new IntFloatPair[2];

public static unsafe void Main (string[] args) {
var pa = ReturnPackedArray();

foreach (var item in pa)
Console.WriteLine(item);
}

[JSPackedArrayReturnValue]
public static IntFloatPair[] ReturnPackedArray () {
return PackedArray;
}
}
27 changes: 27 additions & 0 deletions Tests/FailingTestCases/ReturnPackedArrayAsNormalArray.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using JSIL.Meta;

public struct IntFloatPair {
public int Int;
public float Float;

public override string ToString () {
return String.Format("Int={0:0000}, Float={1:000.000}", Int, Float);
}
}

public static class Program {
[JSPackedArray]
public static IntFloatPair[] PackedArray = new IntFloatPair[2];

public static unsafe void Main (string[] args) {
var pa = ReturnPackedArray();

foreach (var item in pa)
Console.WriteLine(item);
}

public static IntFloatPair[] ReturnPackedArray () {
return PackedArray;
}
}
2 changes: 2 additions & 0 deletions Tests/Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@
<None Include="SimpleTestCases\StringFormatCustomPlacesNegative.cs" />
<None Include="FailingTestCases\PassPackedArrayAsNormalArrayArgument.cs" />
<None Include="FailingTestCases\PassNormalArrayAsPackedArrayArgument.cs" />
<None Include="FailingTestCases\ReturnNormalArrayAsPackedArray.cs" />
<None Include="FailingTestCases\ReturnPackedArrayAsNormalArray.cs" />
<Compile Include="GenericTestFixture.cs" />
<None Include="SimpleTestCases\GenericCreateInstance.cs" />
<None Include="SimpleTestCases\GenericSelfConstraint.cs" />
Expand Down

0 comments on commit ecdac93

Please sign in to comment.