Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localsinit #24723

Merged
merged 9 commits into from
Feb 22, 2018
3 changes: 2 additions & 1 deletion src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1346,7 +1346,7 @@ private static MethodBody GenerateMethodBody(
var localSlotManager = new LocalSlotManager(variableSlotAllocatorOpt);
var optimizations = compilation.Options.OptimizationLevel;

ILBuilder builder = new ILBuilder(moduleBuilder, localSlotManager, optimizations);
ILBuilder builder = new ILBuilder(moduleBuilder, localSlotManager, optimizations, method.LocalsAreZeroed);
DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance();
try
{
Expand Down Expand Up @@ -1460,6 +1460,7 @@ private static MethodBody GenerateMethodBody(
builder.RealizedSequencePoints,
debugDocumentProvider,
builder.RealizedExceptionHandlers,
builder.LocalsAreZeroed,
builder.GetAllScopes(),
builder.HasDynamicLocal,
importScopeOpt,
Expand Down
11 changes: 11 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,17 @@ public virtual bool IsTupleMethod
}
}

/// <summary>
/// Returns true if locals are to be initialized
/// </summary>
public virtual bool LocalsAreZeroed
Copy link
Contributor

@AlekseyTs AlekseyTs Feb 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public virtual bool LocalsAreZeroed [](start = 8, length = 35)

Adding virtual properties at the root is bug prone. We leant to always add abstract properties and have each derived type implement it and then have targeted tests to cover each implementation. I think you'd be better off with the cast in MethodCompiler, otherwise you will need to add and test implementations for retargeted methods, PE methods, etc. Does that worth it? #Closed

Copy link
Contributor

@AlekseyTs AlekseyTs Feb 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we can explicitly throw for all symbols for which we don't expect to call this API. Again this requires this method to have no default implementation. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we keep the virtual property and throw if the default implementation is called? Then only the method in the derived class could be used. I feel like it has the same result with less effort.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with having the property be virtual is future derivations of MethodSymbol. A year from now if a new derivation of MethodSymbol is added the developer may or may not know to re-evaluate the behavior of LocalsAreZeroed in the context of the type. Whether they do or don't comes down to the dillegence of the developer, and code reviewers, involved in the change. By making it abstract though we force the developer to think about this property and make a decision on its value.

Copy link
Contributor

@AlekseyTs AlekseyTs Feb 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess, it is an option to throw from default implementation in this particular situation (for non public API used in very specific place and time in the pipeline), then, assuming that we have adequate test coverage, tests should catch derived classes that fail to override the method. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the end I set it to abstract. We're returning true in some derived classes for now (mostly because of synthesized members).

{
get
{
return true;
}
}

/// <summary>
/// If this is a method of a tuple type, return corresponding underlying method from the
/// tuple underlying type. Otherwise, null.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ public void EnsureMetadataVirtual()

private OverriddenOrHiddenMembersResult _lazyOverriddenOrHiddenMembers;

protected bool _localsAreZeroed;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Protected members should not begin with an _. Really protected members should be Pascal cased but somehow other members here are camelCased. Lots of bad examples.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I'll set it to private. I just realized there's no benefit in it being protected.


// some symbols may not have a syntax (e.g. lambdas, synthesized event accessors)
protected readonly SyntaxReference syntaxReferenceOpt;

Expand Down Expand Up @@ -202,6 +204,7 @@ protected SourceMemberMethodSymbol(NamedTypeSymbol containingType, SyntaxReferen
Debug.Assert(!locations.IsEmpty);

_containingType = containingType;
_localsAreZeroed = true;
this.syntaxReferenceOpt = syntaxReferenceOpt;
this.bodySyntaxReferenceOpt = bodySyntaxReferenceOpt;
this.locations = locations;
Expand Down Expand Up @@ -358,6 +361,14 @@ public override Symbol AssociatedSymbol
}
}

public override bool LocalsAreZeroed
{
get
{
return _localsAreZeroed;
Copy link
Contributor

@AlekseyTs AlekseyTs Feb 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_localsAreZeroed [](start = 23, length = 16)

Why is it safe to return this value? Are we certain attributes have been bound and processed? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}
}

#region Flags

public override bool ReturnsVoid
Expand Down Expand Up @@ -1128,6 +1139,10 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut
arguments.Diagnostics.Add(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsync, arguments.AttributeSyntaxOpt.Location, arguments.AttributeSyntaxOpt.GetErrorDisplayName());
}
}
else if (attribute.IsTargetAttribute(this, AttributeDescription.SkipLocalsInitAttribute))
{
_localsAreZeroed &= false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not set this directly to false here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a point. I don't know why I did that.

Copy link
Contributor

@AlekseyTs AlekseyTs Feb 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_localsAreZeroed &= false; [](start = 16, length = 26)

It feels like we should follow the pattern for other well-known attributes and keep this information in attribute data. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made some changes. I followed the pattern from other simple boolean attributes like DynamicSecurityMethodAttribute and SuppressUnmanagedCodeSecurityAttribute.

}
else
{
var compilation = this.DeclaringCompilation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8559,6 +8559,105 @@ public static int Main()

#endregion

#region SkipLocalsInitAttribute

[Fact]
public void SkipLocalsInitOnMethod()
{
var source = @"
namespace System.Runtime.CompilerServices
{
public class SkipLocalsInitAttribute : System.Attribute
{
}
}

public class C
{
[System.Runtime.CompilerServices.SkipLocalsInitAttribute]
public void M_skip()
{
int x = 2;
x = x + x + x;
}

public void M_init()
{
int x = 2;
x = x + x + x;
}
}
";

var comp = CompileAndVerify(source, verify: Verification.Fails);

comp.VerifyIL("C.M_init", @"
{
// Code size 9 (0x9)
.maxstack 2
.locals init (int V_0) //x
IL_0000: ldc.i4.2
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldloc.0
IL_0004: add
IL_0005: ldloc.0
IL_0006: add
IL_0007: stloc.0
IL_0008: ret
}", realIL: true);

comp.VerifyIL("C.M_skip", @"
{
// Code size 9 (0x9)
.maxstack 2
.locals (int V_0) //x
IL_0000: ldc.i4.2
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldloc.0
IL_0004: add
IL_0005: ldloc.0
IL_0006: add
IL_0007: stloc.0
IL_0008: ret
}", realIL: true);

comp.VerifyIL("C.M_init", @"
{
// Code size 9 (0x9)
.maxstack 2
.locals init (int V_0) //x
IL_0000: ldc.i4.2
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldloc.0
IL_0004: add
IL_0005: ldloc.0
IL_0006: add
IL_0007: stloc.0
IL_0008: ret
}", realIL: false);

comp.VerifyIL("C.M_skip", @"
{
// Code size 9 (0x9)
.maxstack 2
.locals (int V_0) //x
IL_0000: ldc.i4.2
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldloc.0
IL_0004: add
IL_0005: ldloc.0
IL_0006: add
IL_0007: stloc.0
IL_0008: ret
}", realIL: false);
}

#endregion

[Fact, WorkItem(807, "https://github.com/dotnet/roslyn/issues/807")]
public void TestAttributePropagationForAsyncAndIterators_01()
{
Expand Down
6 changes: 5 additions & 1 deletion src/Compilers/Core/Portable/CodeGen/ILBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ internal sealed partial class ILBuilder
private SyntaxTree _lastSeqPointTree;

private readonly SmallDictionary<object, LabelInfo> _labelInfos;
private readonly bool _localsAreZeroed;
private int _instructionCountAtLastLabel = -1;

// This data is only relevant when builder has been realized.
Expand Down Expand Up @@ -62,7 +63,7 @@ internal sealed partial class ILBuilder
// created, in particular for leader blocks in exception handlers.
private bool _pendingBlockCreate;

internal ILBuilder(ITokenDeferral module, LocalSlotManager localSlotManager, OptimizationLevel optimizations)
internal ILBuilder(ITokenDeferral module, LocalSlotManager localSlotManager, OptimizationLevel optimizations, bool localsAreZeroed)
{
Debug.Assert(BitConverter.IsLittleEndian);

Expand All @@ -75,8 +76,11 @@ internal ILBuilder(ITokenDeferral module, LocalSlotManager localSlotManager, Opt

_labelInfos = new SmallDictionary<object, LabelInfo>(ReferenceEqualityComparer.Instance);
_optimizations = optimizations;
_localsAreZeroed = localsAreZeroed;
}

public bool LocalsAreZeroed => _localsAreZeroed;
Copy link
Contributor

@AlekseyTs AlekseyTs Feb 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public bool LocalsAreZeroed => _localsAreZeroed; [](start = 8, length = 48)

It looks like it is not necessary to have this property on ILBuilder or have it inside ILBuilder because ILBuilder itself doen't take any advantage of it. #Closed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, it looks like ILBuilderToString is using this property.


In reply to: 167670235 [](ancestors = 167670235)


private BasicBlock GetCurrentBlock()
{
Debug.Assert(!_pendingBlockCreate || (_currentBlock == null));
Expand Down
5 changes: 4 additions & 1 deletion src/Compilers/Core/Portable/CodeGen/MethodBody.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal sealed class MethodBody : Cci.IMethodBody
private readonly ushort _maxStack;
private readonly ImmutableArray<Cci.ILocalDefinition> _locals;
private readonly ImmutableArray<Cci.ExceptionHandlerRegion> _exceptionHandlers;
private readonly bool _localsAreZeroed;

// Debug information emitted to Release & Debug PDBs supporting the debugger, EEs and other tools:
private readonly ImmutableArray<Cci.SequencePoint> _sequencePoints;
Expand Down Expand Up @@ -50,6 +51,7 @@ public MethodBody(
SequencePointList sequencePoints,
DebugDocumentProvider debugDocumentProvider,
ImmutableArray<Cci.ExceptionHandlerRegion> exceptionHandlers,
bool localsAreZeroed,
ImmutableArray<Cci.LocalScope> localScopes,
bool hasDynamicLocalVariables,
Cci.IImportScope importScopeOpt,
Expand All @@ -72,6 +74,7 @@ public MethodBody(
_methodId = methodId;
_locals = locals;
_exceptionHandlers = exceptionHandlers;
_localsAreZeroed = localsAreZeroed;
_localScopes = localScopes;
_hasDynamicLocalVariables = hasDynamicLocalVariables;
_importScopeOpt = importScopeOpt;
Expand Down Expand Up @@ -102,7 +105,7 @@ public MethodBody(

ImmutableArray<Cci.ExceptionHandlerRegion> Cci.IMethodBody.ExceptionRegions => _exceptionHandlers;

bool Cci.IMethodBody.LocalsAreZeroed => true;
bool Cci.IMethodBody.LocalsAreZeroed => _localsAreZeroed;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that this may vary, it should be another key in the method body cache. Just having same IL is not enough to say that methods may share the body.
Look at SerializeMethodBody

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder how this could be tested. We need to make sure the caching is not interfering.

Perhaps we can use code that relies on the zero init happening or not happening (probably using stackalloc or "out" parameters in VB), then we may just run bunch of similar methods that only differ in this bit and see if results are as expected?


In reply to: 167321124 [](ancestors = 167321124)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point, but I haven't tested to see whether it's likely that you get non-zero memory when running stackalloc. Our tests would have a dependency on having non-zero random memory, wouldn't they?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was talking to @agocke about this. We use a body from the cache if we can guarantee that localSignatureHandleOpt.IsNil returns true. localSignatureHandleOpt is obtained from SerializeLocalVariablesSignature, which seems to return a default object only if there are no locals. Maybe adding another check is not necessary. I still don't know how to test it, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AreLocalsZeroed bool is now being used during IL mapping in cache. A test was added to check if method bodies that differ only by SkipLocalsInitAttribute have different Relative Virtual Addresses. The test was failing before the changes in the cache mapping and it's working now.


ImmutableArray<Cci.ILocalDefinition> Cci.IMethodBody.LocalVariables => _locals;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ static AttributeDescription()

private static readonly byte[][] s_signaturesOfExperimentalAttribute = { s_signature_HasThis_Void };
private static readonly byte[][] s_signaturesOfExcludeFromCodeCoverageAttribute = { s_signature_HasThis_Void };
private static readonly byte[][] s_signaturesOfSkipLocalsInitAttribute = { s_signature_HasThis_Void };

// early decoded attributes:
internal static readonly AttributeDescription OptionalAttribute = new AttributeDescription("System.Runtime.InteropServices", "OptionalAttribute", s_signaturesOfOptionalAttribute);
Expand Down Expand Up @@ -515,5 +516,6 @@ static AttributeDescription()
internal static readonly AttributeDescription DeprecatedAttribute = new AttributeDescription("Windows.Foundation.Metadata", "DeprecatedAttribute", s_signaturesOfDeprecatedAttribute);
internal static readonly AttributeDescription ExperimentalAttribute = new AttributeDescription("Windows.Foundation.Metadata", "ExperimentalAttribute", s_signaturesOfExperimentalAttribute);
internal static readonly AttributeDescription ExcludeFromCodeCoverageAttribute = new AttributeDescription("System.Diagnostics.CodeAnalysis", "ExcludeFromCodeCoverageAttribute", s_signaturesOfExcludeFromCodeCoverageAttribute);
internal static readonly AttributeDescription SkipLocalsInitAttribute = new AttributeDescription("System.Runtime.CompilerServices", "SkipLocalsInitAttribute", s_signaturesOfSkipLocalsInitAttribute);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ protected override Compilation GetCompilationForEmit(IEnumerable<string> source,
throw new NotImplementedException();
}

internal override string VisualizeRealIL(IModuleSymbol peModule, CodeAnalysis.CodeGen.CompilationTestData.MethodData methodData, IReadOnlyDictionary<int, string> markers)
internal override string VisualizeRealIL(IModuleSymbol peModule, CodeAnalysis.CodeGen.CompilationTestData.MethodData methodData, IReadOnlyDictionary<int, string> markers, bool localsAreZeroed)
{
throw new NotImplementedException();
}
Expand Down
8 changes: 4 additions & 4 deletions src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -944,9 +944,9 @@ internal static string GetDocumentationCommentText(CSharpCompilation compilation

#region IL Validation

internal override string VisualizeRealIL(IModuleSymbol peModule, CompilationTestData.MethodData methodData, IReadOnlyDictionary<int, string> markers)
internal override string VisualizeRealIL(IModuleSymbol peModule, CompilationTestData.MethodData methodData, IReadOnlyDictionary<int, string> markers, bool localsAreZeroed)
{
return VisualizeRealIL((PEModuleSymbol)peModule, methodData, markers);
return VisualizeRealIL((PEModuleSymbol)peModule, methodData, markers, localsAreZeroed);
}

/// <summary>
Expand All @@ -959,7 +959,7 @@ internal override string VisualizeRealIL(IModuleSymbol peModule, CompilationTest
/// - winmd
/// - global methods
/// </remarks>
internal unsafe static string VisualizeRealIL(PEModuleSymbol peModule, CompilationTestData.MethodData methodData, IReadOnlyDictionary<int, string> markers)
internal unsafe static string VisualizeRealIL(PEModuleSymbol peModule, CompilationTestData.MethodData methodData, IReadOnlyDictionary<int, string> markers, bool localsAreZeroed)
{
var typeName = GetContainingTypeMetadataName(methodData.Method);
// TODO (tomat): global methods (typeName == null)
Expand Down Expand Up @@ -1000,7 +1000,7 @@ internal unsafe static string VisualizeRealIL(PEModuleSymbol peModule, Compilati

var visualizer = new Visualizer(new MetadataDecoder(peModule, peMethod));

visualizer.DumpMethod(sb, maxStack, ilBytes, localDefinitions, ehHandlerRegions, markers);
visualizer.DumpMethod(sb, maxStack, ilBytes, localDefinitions, ehHandlerRegions, markers, localsAreZeroed);

return sb.ToString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ Public MustInherit Class BasicTestBaseBase
Return attributes.Select(Function(a) a.AttributeClass.Name)
End Function

Friend Overrides Function VisualizeRealIL(peModule As IModuleSymbol, methodData As CompilationTestData.MethodData, markers As IReadOnlyDictionary(Of Integer, String)) As String
Friend Overrides Function VisualizeRealIL(peModule As IModuleSymbol, methodData As CompilationTestData.MethodData, markers As IReadOnlyDictionary(Of Integer, String), localsAreZeroed As Boolean) As String
Throw New NotImplementedException()
End Function

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1507,7 +1507,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
optimizations = OptimizationLevel.Release
End If

Dim builder As ILBuilder = New ILBuilder(moduleBuilder, localSlotManager, optimizations)
Dim builder As ILBuilder = New ILBuilder(moduleBuilder, localSlotManager, optimizations, localsAreZeroed:=True)
Copy link
Contributor

@AlekseyTs AlekseyTs Feb 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

localsAreZeroed:=True) [](start = 101, length = 22)

Are we planning to add recognition of the attribute to VB as well? #Pending

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only C#, as far as I know.


Try
Debug.Assert(Not diagnostics.HasAnyErrors)
Expand Down Expand Up @@ -1610,6 +1610,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
builder.RealizedSequencePoints,
debugDocumentProvider,
builder.RealizedExceptionHandlers,
localsAreZeroed:=True,
localScopes,
hasDynamicLocalVariables:=False,
importScopeOpt:=importScopeOpt,
Expand Down
2 changes: 1 addition & 1 deletion src/Test/Utilities/Portable/CommonTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ private void AddReferencedCompilations(IEnumerable<Compilation> referencedCompil

#region IL Verification

internal abstract string VisualizeRealIL(IModuleSymbol peModule, CompilationTestData.MethodData methodData, IReadOnlyDictionary<int, string> markers);
internal abstract string VisualizeRealIL(IModuleSymbol peModule, CompilationTestData.MethodData methodData, IReadOnlyDictionary<int, string> markers, bool localsAreZeroed);

#endregion

Expand Down
6 changes: 3 additions & 3 deletions src/Test/Utilities/Portable/CompilationVerifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ public sealed class CompilationVerifier
public ImmutableArray<byte> EmittedAssemblyData;
public ImmutableArray<byte> EmittedAssemblyPdb;

private readonly Func<IModuleSymbol, CompilationTestData.MethodData, IReadOnlyDictionary<int, string>, string> _visualizeRealIL;
private readonly Func<IModuleSymbol, CompilationTestData.MethodData, IReadOnlyDictionary<int, string>, bool, string> _visualizeRealIL;

internal CompilationVerifier(
Compilation compilation,
Func<IModuleSymbol, CompilationTestData.MethodData, IReadOnlyDictionary<int, string>, string> visualizeRealIL = null,
Func<IModuleSymbol, CompilationTestData.MethodData, IReadOnlyDictionary<int, string>, bool, string> visualizeRealIL = null,
IEnumerable<ModuleData> dependencies = null)
{
_compilation = compilation;
Expand Down Expand Up @@ -222,7 +222,7 @@ internal string VisualizeIL(CompilationTestData.MethodData methodData, bool real
_lazyModuleSymbol = GetSymbolFromMetadata(targetReference, MetadataImportOptions.All);
}

return _lazyModuleSymbol != null ? _visualizeRealIL(_lazyModuleSymbol, methodData, markers) : null;
return _lazyModuleSymbol != null ? _visualizeRealIL(_lazyModuleSymbol, methodData, markers, _testData.Module.GetMethodBody(methodData.Method).LocalsAreZeroed) : null;
}

public CompilationVerifier VerifyMemberInIL(string methodName, bool expected)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ internal static string ILBuilderToString(

if (!ilStream.IsDefault)
{
visualizer.DumpMethod(sb, builder.MaxStack, ilStream, locals, GetHandlerSpans(builder.RealizedExceptionHandlers), markers);
visualizer.DumpMethod(sb, builder.MaxStack, ilStream, locals, GetHandlerSpans(builder.RealizedExceptionHandlers), markers, builder.LocalsAreZeroed);
}
else
{
Expand Down