NewPhoenixStudent

Hi,

Im generating MSIL code and I want to create a local variable in my method to store a new object. For this I put the follow code

Code Snippet

Phx.Symbols.LocalVariableSymbol objSymbol =

Phx.Symbols.LocalVariableSymbol.New(functionUnit.SymbolTable, 0, Phx.Name.New(

functionUnit.Lifetime, "b"), classType, Phx.Symbols.StorageClass.Auto);



Unfortunately, this code dont insert the local variable in the.locals init. However, if I put


Code Snippet

Phx.Symbols.LocalVariableSymbol objSymbol =

Phx.Symbols.LocalVariableSymbol.New(functionUnit.SymbolTable, 0,

Phx.Name.New(functionUnit.Lifetime, "b"),

typeTable.GetObjectPointerType(classType), Phx.Symbols.StorageClass.Auto);



one variable is added to locals var, but the type is "object&".

Code Snippet

.locals init (object& V_0)


Which is the correct way to do this


Re: Phoenix Local Symbol

Andy Ayers - MSFT

In MSIL code "ref classes" are always represented as object-pointer-to-class type. So I think you are closer with your second snippet.

You don't say which client you're using (is it a pe read-write like mtrace, or are you using the MSIL compiler sample code posted on the forum ) so I can't be sure what is missing.

If you are using the MSIL compiler sample code from the forum, then I probably need to understand how you created class_type and what you are doing with objSymbol.

If you are doing something like mtrace, below is a code snippet where I modify the latter part of the mtrace sample InstrumentAfter method to use a new local variable. The original code simply fed the result of the LDSTR into the call; we now insert a STLOC/LDLOC pair in between.

The only trick here is to give the local a frame location; to do this you need to count the current number of locals in the function.

Code Snippet

// Generate:

// ldstr "..."

// stloc N

int localsCount = 0;

foreach (Phx.Symbols.Symbol symbol in functionUnit.SymbolTable.LocalIdMap.InternalMap)

{

if (symbol.IsLocalVariableSymbol

&& (symbol.AsLocalVariableSymbol.StorageClass == Phx.Symbols.StorageClass.Auto))

{

localsCount++;

}

}

Phx.Symbols.LocalVariableSymbol locSymbol = Phx.Symbols.LocalVariableSymbol.New(

functionUnit.SymbolTable, 0, Phx.Name.New(Phx.GlobalData.GlobalLifetime, "temp"),

stringType, Phx.Symbols.StorageClass.Auto);

locSymbol.Location = Phx.Symbols.FrameLocation.New(functionUnit.Lifetime, localsCount);

Phx.IR.Operand locOpnd = Phx.IR.VariableOperand.New(functionUnit, stringType, locSymbol);

Phx.IR.Instruction ldStr = Phx.IR.Instruction.NewUnaryExpression(functionUnit,

Phx.Targets.Architectures.Msil.Opcode.ldstr, stringType, strOpnd);

Phx.IR.Instruction stLoc = Phx.IR.Instruction.NewUnary(functionUnit, Phx.Targets.Architectures.Msil.Opcode.stloc,

locOpnd, ldStr.DestinationOperand);

// Generate:

// ldloc N

// call System.Diagnostics.Trace

Phx.IR.Instruction ldLoc = Phx.IR.Instruction.NewUnaryExpression(functionUnit, Phx.Targets.Architectures.Msil.Opcode.ldloc,

stringType, locOpnd);

Phx.IR.Instruction call = Phx.IR.Instruction.NewCall(functionUnit,

Phx.Targets.Architectures.Msil.Opcode.call,

this.traceFuncSym);

call.AppendSource(ldLoc.DestinationOperand);

instruction.InsertAfter(call);

instruction.InsertAfter(ldLoc);

instruction.InsertAfter(stLoc);

instruction.InsertAfter(ldStr);

// Assign registers.

ldStr.DestinationOperand.Register = Phx.Targets.Architectures.Msil.Register.SR0;

stLoc.SourceOperand.Register = Phx.Targets.Architectures.Msil.Register.SR0;

ldLoc.DestinationOperand.Register = Phx.Targets.Architectures.Msil.Register.SR0;

call.GetFirstArgumentOperand().Register = Phx.Targets.Architectures.Msil.Register.SR0;

// Explicitly break the expression temporary link here since we

// assigned registers.

ldStr.DestinationOperand.BreakExpressionTemporary();

ldLoc.DestinationOperand.BreakExpressionTemporary();






Re: Phoenix Local Symbol

NewPhoenixStudent

Im using the MSIL compiler sample. The code that I used to create the class (NewClass) is similar to the used to create the SampleClass in the MSIL compiler sample. The diference is the .ctor method. that I added in this new class. The code for this is :



Code Snippet
//


Phx.Types.FunctionTypeBuilder funcTypeBuilder =
Phx.Types.FunctionTypeBuilder.New(peModuleUnit.TypeTable);
funcTypeBuilder.Begin();
funcTypeBuilder.CallingConventionKind = CallingConventionKind.ClrCall;


//Pointer to the class
Phx.Types.Type pointerClassType = typeTable.GetObjectPointerType(NewClass);

funcTypeBuilder.AppendReturnType(typeTable.VoidType);

Phx.Types.FunctionArgument funcArg =
Phx.Types.FunctionArgument.New(typeTable, FunctionArgumentKind.ThisPoint, pointerClassType);

funcTypeBuilder.AppendArgumentFunctionArgument(funcArg);


Phx.Types.FunctionType functionType = funcTypeBuilder.GetFunctionType();


Phx.Symbols.FunctionSymbol funcSymbol =
Phx.Symbols.FunctionSymbol.New(peModuleUnit.SymbolTable,

0, Phx.Name.New(lifetime, ".ctor"), functionType,

Visibility.GlobalDefinition);

//Set metadatas
fsCtor.IsSpecialName = true;
fsCtor.IsRuntimeSpecialName = true;
fsCtor.IsHideBySignature = true;

// Create the functionUnit
Phx.FunctionUnit functionUnit =
Phx.FunctionUnit.New(funcSymbol, Phx.CodeGenerationMode.IJW, typeTable,
peModuleUnit.MsilRuntime.Architecture, peModuleUnit.MsilRuntime,
peModuleUnit, countFunction++);

funcSymbol.FunctionUnit = functionUnit;

peModuleUnit.AppendChildUnit(functionUnit);

Phx.Symbols.Table functionSymbolTable =
Phx.Symbols.Table.New(functionUnit, 64, false);

functionUnit.AllocateLifetime();

LocalVariableSymbol thisSymbol =
Phx.Symbols.LocalVariableSymbol.New(functionSymbolTable,
0, Phx.Name.New(functionUnit.Lifetime, "this"), pointerClassType,
Phx.Symbols.StorageClass.Parameter);
thisSymbol.IsThisParameter = true;

// Create some basic IR....

Phx.IR.Instruction startInstruction = functionUnit.FirstInstruction;

Phx.IR.Instruction endInstruction = functionUnit.LastInstruction;

Phx.IR.LabelInstruction enterInstruction =
Phx.IR.LabelInstruction.New(functionUnit, Phx.Common.Opcode.EnterFunction,
funcSymbol);

enterInstruction.AppendDestination(Phx.IR.VariableOperand.New(
functionUnit, pointerClassType, thisSymbol));

startInstruction.InsertAfter(enterInstruction);

startInstruction.AppendLabelSource(Phx.IR.LabelOperandKind.Technical,
Phx.IR.LabelOperand.New(functionUnit, enterInstruction));

//Build the FunctionSymbol to .ctor method. listParamTypes in this case is null
FunctionSymbol fsObjectActor =
ImportTypes("mscorlib", "System.Object", ".ctor", listParamTypes,
typeTable.VoidType);

Instruction instCallActor =
Instruction.NewCall(fsCtor.FunctionUnit, Phx.Common.Opcode.Call, fsObjectActor);

MemoryOperand thisMemoryOperand = MemoryOperand.New(funcCtor, pointerClassType ,
thisSymbol, null, 0, Alignment.NaturalAlignment(pointerClassType),
funcCtor.AliasInfo.InstanceMemoryTag, funcCtor.SafetyInfo.SafeTag);

instCallActor.AppendSource(thisMemoryOperand);
startInstruction.InsertAfter(instCallActor);

exitInstruction =
Phx.IR.LabelInstruction.New(functionUnit, Phx.Common.Opcode.ExitFunction);

Phx.IR.Instruction retInstr = Phx.IR.BranchInstruction.NewReturn(functionUnit,
Phx.Common.Opcode.Return, exitInstruction);
instCallActor.InsertAfter(retInstr);

functionUnit.LastInstruction.InsertBefore(exitInstruction);
functionUnit.FinishCreation();



*OBS: Debug instructions were omitted


To create a new object of this class I used the code below.

Code Snippet

// Instruction newobj. fsCtor is the .ctor FunctionSymbol create before.

Instruction newObjInst =
Instruction.NewCall(functionUnit, Phx.Targets.Architectures.Msil.Opcode.newobj,
fsCtor);

Phx.Types.Type pointerClassType = typeTable.GetObjectPointerType(NewClass);


Phx.Symbols.LocalVariableSymbol objSymbol =

Phx.Symbols.LocalVariableSymbol.New(functionUnit.SymbolTable, 0, Phx.Name.New(
functionUnit.Lifetime, "b"), pointerClassType,
Phx.Symbols.StorageClass.Auto);

objSymbol.Location = Phx.Symbols.FrameLocation.New(functionUnit.Lifetime, 0);

VariableOperand objVarOp =
VariableOperand.New(functionUnit, pointerClassType, objSymbol);

newObjInst.AppendDestination(objVarOp);

// To insert the instrucion in the instrunctions list




So, the generate code is:

Code Snippet


.method public static void Main(string[] args) cil managed
{
.entrypoint
// Code size 17 (0x11)
.maxstack 1
.locals init (object& V_0)
IL_0000: newobj instance void SecondClass::.ctor()
IL_0005: stloc.0
IL_0006: br IL_000b
IL_000b: br IL_0010
IL_0010: ret
} // end of method MainClass::Main




I believe that the local variable type should be "class NewClass", shouldnt it

What am I doing wrong Please, somebody help me!!!









Re: Phoenix Local Symbol

gavelino

Hi, Im having the same problem. Although my code seems to work, it is doing pointer arithmetic to acces the fields. For example, the code below assign the integer value 10 to the field y of SecondClass.



Code Snippet

.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 26 (0x1a)
.maxstack 2
.locals init (object& V_0,
int32 V_1)
IL_0000: newobj instance void SecondClass::.ctor()
IL_0005: stloc.0
IL_0006: ldloca.s V_0
IL_0008: ldc.i4.4
IL_0009: add
IL_000a: stloc.1
IL_000b: ldloc.1
IL_000c: ldc.i4.s 10
IL_000e: stind.i4
IL_0019: ret
} // end of method MainClass::Main



SecondClass

Class SecondClass
{
.ctor();
int x;
int y;
}


Does this happen because the object is handled by a pointer What can I do to resolve this

Please, Im really need this answer!!!













Re: Phoenix Local Symbol

Andy Ayers - MSFT

NewPhoenixStudent, I have some bad news.

It looks like the approach taken in the MsilCompiler sample doesn't work very well in more complicated cases. The root of the problem is that Phoenix actually has two scenarios where it emits MSIL -- one (call it "c2") to support compiling /clr, and one in the PE read/write case. The MsilCompiler sample mixes and matches components from the two scenarios, and while you can get pretty far that way, there are some limitations.

In this particular case, the code ends up emitting the local signatures "c2-style" which makes certain assumptions that don't hold true. In the debugger I can force it to emit things "PE read/write style" and it gets us a bit farther before assumptions made in that scenario also fail to hold.

I think it is possible to get farther along by not mixing scenario components and just sticking with PE read/write the entire way. This will mean emitting LIR instead of HIR, but for MSIL that's not a big conceptual shift. I would like to revise the MsilCompiler sample to show how this is done but can't really promise anything.






Re: Phoenix Local Symbol

Andy Ayers - MSFT

Gavelino, how did you describe setting the value of SecondClass.y in IR






Re: Phoenix Local Symbol

gavelino

The code used to insert the field y in the SecondClass is described below.

Code Snippet

// field is an instance of FieldStruct {string name, Type type, Symbols.Access access}

//Where field.name= "y", field.type = typeTable.Int32Type e field.access = Access.Public


Phx.Symbols.Table symTable = peModuleUnit.SymbolTable;

FieldSymbol fieldSymbol =
FieldSymbol.New(symTable, 0, Name.New(lifetime, field.name), field.type);

fieldSymbol.BitOffset = GetNextBitOffset(secondClassType);

fieldSymbol.Access = field.access;
Phx.Types.Field fieldType = classType.AppendFieldSymbol(fieldSymbol);
secondClassType.TypeSymbol.InsertInLexicalScope(fieldSymbol,
Phx.Name.New(lifetime, field.name));



int GetNextBitOffset(AggregateType classType)
{
int bitOffset = 0;
FieldSymbol fieldSym = classType.FieldSymbolList;
while (fieldSym!=null)
{
bitOffset += (int)Alignment.NaturalAlignment(fieldSym.Type).BitSize;
fieldSym = fieldSym.NextTypeFieldSymbol;
}
return bitOffset;
}




and to set the value

Code Snippet

// Instanciate the SecondClass object

Instruction newObjInst = Instruction.NewCall(functionUnit,

Phx.Targets.Architectures.Msil.Opcode.newobj, ctorSymbol);


Phx.Types.Type pointerType = typeTable.GetObjectPointerType(secondClassType);


Phx.Symbols.LocalVariableSymbol objSymbol =
Phx.Symbols.LocalVariableSymbol.NewAuto(functionUnit.SymbolTable, 0,
Name.New(functionUnit.Lifetime, varName), pointerType);


VariableOperand objVarOp = VariableOperand.New(functionUnit, pointerType, objSymbol);

newObjInst.AppendDestination(objVarOp);

functionUnit.LastInstruction.InsertBefore(newObjInst);



//Assign field
Field field = getFieldSymbol(classType, fieldName).Field;

VariableOperand fieldVarOp = VariableOperand.New(functionUnit, field, objSymbol);
Instruction assignFieldInst =
Instruction.NewUnary(functionUnit,Phx.Common.Opcode.Assign, fieldVarOp,
ImmediateOperand.New(functionUnit, typeTable.Int32Type, 10));
functionUnit.LastInstruction.InsertBefore(assignFieldInst);


//Obs: getFielSymbol find the field in the class.





Im a lot worried with you said to NewPhoenixStudent. My objective is to build a compiler that generates MSIL code for a small functional language, to do this Im using the MSIL compiler sample. How big is the problem with the MSIL compiler My time is short, what approach would you recommend me

Thank you!!









Re: Phoenix Local Symbol

Andy Ayers - MSFT

I haven't tried this, but I think that the arithmetic shows up because you are assigning a bit offset to the field. In MSIL code the structure layout is usually done by the runtime and so when compiling MSIL the offsets are not known.

So, just try deleting the line:

Code Snippet
fieldSymbol.BitOffset = GetNextBitOffset(secondClassType);

and see what happens.

As for the problem with local signatures -- I share your worries, but so long as you are ok with producing non-verifiable code I think things may work out ok.




Re: Phoenix Local Symbol

gavelino

Hi Andy,

I deleted the instruction, but it doesnt work. Without to set the BitOffSet all the fields are stored in the same place, replacing the first. I think this happen because the object is handled with a pointer. Even without bitOffSet information the code generates use stind and ldind opcodes, which need a address pointers.

My research needs to work with verifiable code. What can I do









Re: Phoenix Local Symbol

Andy Ayers - MSFT

Hi all -- I am happy to say there is a workaround-fix for the local signature problem. All credit for this belongs to Weiping who is one of the main developers of the PE read-write capability in Phoenix.

There are two parts to this. First, any class you import needs to have the IsSelfDescribing property set on the AggregateType. This tells Phoenix that the type derives from System.Object.

Second, you need to manually assign stack slots and generate the local variable signature. Replace these lines:

Code Snippet
// Cleanup after encoding

peModuleUnit.CloseUnit(functionUnit);

in the original MsilCompiler code with the following:

Code Snippet

// Force creation of a new signature

((Phx.Targets.Runtimes.Vccrt.Win.Msil.Frame)functionUnit.Frame).LocalVarSigTok = 0;


// Work around an assertion by assigning byte offsets
.

int i = 0;

foreach (Phx.Symbols.Symbol localSymbol in functionUnit.SymbolTable.LocalIdMap.InternalMap)

{

if (!localSymbol.IsLocalVariableSymbol) continue;

if (!localSymbol.AsLocalVariableSymbol.IsAuto) continue;

localSymbol.Location.AsFrameLocation.ByteOffset = i++;

}

Phx.PE.Writer.UpdateEncodedIR(functionUnit);

Phx.Metadata.SignatureEmitter.EncodeLocalSignature(functionUnit);

functionUnit.ReleaseLifetime();

and your local signatures should be good.





Re: Phoenix Local Symbol

gavelino

Hi,

First, thanks for the effort. But, here the problem isnt resolved. Now, the local signature show the message "class [ERROR! NIL TOKEN] V_0".
Other question, do you think this solution can resolve the problem to access the fields






Re: Phoenix Local Symbol

Andy Ayers - MSFT

Oops, I left out one important step. You also need to call

Code Snippet
peModuleUnit.PreAssignTypeTokens();

sometime between creating the new types and updating the encoded IR. Otherwise (as you saw) your new types will just have zeros for their token values.

I think the problem with fields is unrelated but I haven't had a chance to look at it yet.






Re: Phoenix Local Symbol

gavelino

Now, its ok.

Thank you very much!!!




Re: Phoenix Local Symbol

gavelino

Andy,

Did you have any progress with the fields problem Why the generated code makes arithmetic pointer to access a field

Thanks.




Re: Phoenix Local Symbol

Andy Ayers - MSFT

Yes, I worked on it some, without much success (or I would have just said "here's the answer!"). I think the only way forward is to use a small bit of LIR to get things working as expected.