/// <summary> /// Gets the memory. /// </summary> /// <param name="operand">The operand.</param> /// <param name="emit">if set to <c>true</c> [emit].</param> /// <returns></returns> private Memory GetMemory(Operand operand) { Memory address = null; if (operand is FieldOperand) { address = this.GetAddress(operand as FieldOperand); } else if (operand is Argument) { address = this.GetAddress(operand as Argument); } else if (operand is Local) { address = this.GetAddress(operand as Local); } else if (operand is IR.Operands.Register) { address = this.GetAddress(operand as IR.Operands.Register); } else { throw new NotImplementedEngineException("Wrong '" + operand.ToString() + "' Operand."); } if (operand.InternalType == InternalType.I1 || operand.InternalType == InternalType.U1) { address = new ByteMemory(address); } else if (operand.InternalType == InternalType.I2 || operand.InternalType == InternalType.U2) { address = new WordMemory(address); } else if (operand.InternalType == InternalType.I4 || operand.InternalType == InternalType.U4 || operand.InternalType == InternalType.I || operand.InternalType == InternalType.U || operand.InternalType == InternalType.ValueType || operand.InternalType == InternalType.O || operand.InternalType == InternalType.M || operand.InternalType == InternalType.SZArray || operand.InternalType == InternalType.Array) { address = new DWordMemory(address); } else if (operand.InternalType == InternalType.I8 || operand.InternalType == InternalType.U8) { address = new DWordMemory(address); } else { throw new NotImplementedEngineException("'" + operand.InternalType + "' not supported."); } return(address); }
/// <summary> /// Common implementation for IL instructions which load a value onto the IL evaluation stack. /// </summary> private void Load (IR.Operands.Register assignee, InternalType sourceType, Memory memory) { switch (sourceType) { case InternalType.I1: this.assembly.MOVSX (R32.EAX, new ByteMemory (memory)); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case InternalType.U1: this.assembly.MOVZX (R32.EAX, new ByteMemory (memory)); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case InternalType.I2: this.assembly.MOVSX (R32.EAX, new WordMemory (memory)); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case InternalType.U2: this.assembly.MOVZX (R32.EAX, new WordMemory (memory)); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case InternalType.I4: case InternalType.U4: case InternalType.I: case InternalType.U: case InternalType.O: case InternalType.M: case InternalType.SZArray: case InternalType.Array: this.assembly.MOV (R32.EAX, new DWordMemory (memory)); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case InternalType.I8: case InternalType.U8: DWordMemory source = new DWordMemory (memory); source.DisplacementDelta = 4; Memory destination = this.GetAddress (assignee); destination.DisplacementDelta = 4; this.assembly.MOV (R32.EAX, new DWordMemory (memory)); this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); this.assembly.MOV (R32.EAX, new DWordMemory (source)); this.assembly.MOV (new DWordMemory (destination), R32.EAX); break; case InternalType.ValueType: uint size = (uint) assignee.Type.Size; if (size == 4) { this.assembly.MOV (R32.EAX, new DWordMemory (memory)); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); } else { this.assembly.PUSH (R32.ECX); this.assembly.PUSH (R32.ESI); this.assembly.PUSH (R32.EDI); this.assembly.LEA (R32.ESI, new DWordMemory (memory)); if (assignee.IsRegisterSet) this.assembly.MOV (R32.EDI, Assembly.GetRegister (assignee.Register)); else this.assembly.LEA (R32.EDI, new DWordMemory (this.GetAddress (assignee))); this.assembly.MOV (R32.ECX, size); this.assembly.CLD (); this.assembly.REP (); this.assembly.MOVSB (); this.assembly.POP (R32.EDI); this.assembly.POP (R32.ESI); this.assembly.POP (R32.ECX); } break; case InternalType.R4: case InternalType.R8: case InternalType.F: case InternalType.TypedReference: default: throw new NotImplementedEngineException ("Load not supported for InternalType." + sourceType); } }
/// <summary> /// Encodes the IL 'call', 'calli', and 'callvirt' instructions /// </summary> private void Call (SharpOS.AOT.IR.Instructions.Call call) { if (call.IsSpecialCase) { if (this.assembly.IsInstruction (call.Method.Class.TypeFullName)) this.HandleAssemblyStub (call); else this.HandleBuiltIns (call); return; } if (call.Method.Class.IsArray && call.Method.SkipProcessing) { this.ArrayCalls (call); return; } // TODO add support for call/callvirt/calli/jmp and for tail./constrained. // Perform a null check for non-static methods if (!(call.Method.MethodDefinition as Mono.Cecil.MethodDefinition).IsStatic) { IR.Operands.Register identifier = call.Use [0] as IR.Operands.Register; if (identifier.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (identifier.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (identifier))); NullCheck (R32.EAX); } PushCallParameters (call); IR.Operands.Register assignee = call.Def as IR.Operands.Register; if (call.Method.IsReturnTypeBigValueType) { this.assembly.LEA (R32.EAX, this.GetAddress (assignee)); this.assembly.PUSH (R32.EAX); } if (call is Callvirt && (call.Method.IsNewSlot || call.Method.IsVirtual)) { IR.Operands.Register _this = call.Use [0] as IR.Operands.Register; if (_this.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (_this.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (_this))); if (call.Method.InterfaceMethodNumber == -1) { // Do a normal vtable call int address = this.assembly.Engine.VTableSize + this.assembly.IntSize * call.Method.VirtualSlot; // Get the Object's VTable this.assembly.MOV (R32.EAX, new DWordMemory (null, R32.EAX, null, 0)); // Call virtual method using the table in the Object's VTable this.assembly.CALL (new DWordMemory (null, R32.EAX, null, 0, address)); } else { // Do a IMT lookup call for interface method int address = this.assembly.IntSize * call.Method.InterfaceMethodKey + this.assembly.Engine.ObjectSize; // Get the Object's VTable this.assembly.MOV (R32.EAX, new DWordMemory (null, R32.EAX, null, 0)); // Get the Object's ITable this.assembly.MOV (R32.EAX, new DWordMemory (null, R32.EAX, null, 0, this.assembly.IntSize * 4)); // IMT key in case call hits a colision resolving stub this.assembly.MOV (R32.ECX, (uint) call.Method.InterfaceMethodNumber); // Call virtual method using the table in the Object's ITable this.assembly.CALL (new DWordMemory (null, R32.EAX, null, 0, address)); } } else assembly.CALL (call.Method.AssemblyLabel); PopCallParameters (call); if (assignee != null) { switch (assignee.InternalType) { case InternalType.I: case InternalType.M: case InternalType.O: case InternalType.I4: case InternalType.SZArray: case InternalType.Array: if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case InternalType.I8: Memory assigneeMemory = this.GetAddress (assignee); DWordMemory low = new DWordMemory (assigneeMemory); this.assembly.MOV (low, R32.EAX); DWordMemory high = new DWordMemory (assigneeMemory); high.DisplacementDelta = 4; this.assembly.MOV (high, R32.EDX); break; case InternalType.ValueType: // It is already handled above break; default: throw new NotImplementedEngineException ("Call assignee handling for InternalType." + assignee.InternalType); } } }
/// <summary> /// Implements the 'mul' IL instruction, which pops two values, multiplies them, and pushes /// the result. /// </summary> private void Mul (IR.Instructions.Mul instruction) { IR.Operands.Register assignee = instruction.Def as IR.Operands.Register; IR.Operands.Register first = instruction.Use [0] as IR.Operands.Register; IR.Operands.Register second = instruction.Use [1] as IR.Operands.Register; switch (assignee.InternalType) { case InternalType.I: case InternalType.I4: if (first.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (first.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (first))); if (instruction.MulType == IR.Instructions.Mul.Type.Mul || instruction.MulType == IR.Instructions.Mul.Type.MulUnsignedWithOverflowCheck ) { if (second.IsRegisterSet) this.assembly.IMUL (R32.EAX, Assembly.GetRegister (second.Register)); else this.assembly.IMUL (R32.EAX, new DWordMemory (this.GetAddress (second))); } else throw new NotImplementedEngineException ("Mul not supported for Mul.Type." + instruction.MulType); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case InternalType.I8: if (instruction.MulType == IR.Instructions.Mul.Type.Mul) { Memory firstMemory = this.GetAddress (first); DWordMemory firstHigh = new DWordMemory (firstMemory); firstHigh.DisplacementDelta = 4; DWordMemory firstLow = new DWordMemory (firstMemory); Memory secondMemory = this.GetAddress (second); DWordMemory secondHigh = new DWordMemory (secondMemory); secondHigh.DisplacementDelta = 4; DWordMemory secondLow = new DWordMemory (secondMemory); this.assembly.PUSH (secondHigh); this.assembly.PUSH (secondLow); this.assembly.PUSH (firstHigh); this.assembly.PUSH (firstLow); this.assembly.CALL (Assembly.HELPER_LMUL); this.assembly.ADD (R32.ESP, 16); Memory assigneeMemory = this.GetAddress (assignee); this.assembly.MOV (new DWordMemory (assigneeMemory), R32.EAX); assigneeMemory.DisplacementDelta = 4; this.assembly.MOV (new DWordMemory (assigneeMemory), R32.EDX); } else throw new NotImplementedEngineException ("Mul not supported for Mul.Type." + instruction.MulType); break; default: throw new NotImplementedEngineException ("Mul not supported for InternalType." + assignee.InternalType); } }
/// <summary> /// /// </summary> private void ConditionCheck (IR.Instructions.ConditionCheck instruction) { IR.Operands.Register assignee = instruction.Def as IR.Operands.Register; IR.Operands.Register first = instruction.Use [0] as IR.Operands.Register; IR.Operands.Register second = instruction.Use [1] as IR.Operands.Register; string errorLabel = assembly.GetCMPLabel; string okLabel = assembly.GetCMPLabel; string endLabel = assembly.GetCMPLabel; switch (first.InternalType) { case InternalType.M: case InternalType.O: case InternalType.I: case InternalType.I4: case InternalType.SZArray: case InternalType.Array: if (first.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (first.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (first))); if (second.IsRegisterSet) this.assembly.MOV (R32.EDX, Assembly.GetRegister (second.Register)); else this.assembly.MOV (R32.EDX, new DWordMemory (this.GetAddress (second))); this.assembly.CMP (R32.EAX, R32.EDX); RelationalTypeCMP (instruction.RelationalType, okLabel); break; case InternalType.I8: DWordMemory firstAddress = new DWordMemory (this.GetAddress (first)); firstAddress.DisplacementDelta = 4; DWordMemory secondAddress = new DWordMemory (this.GetAddress (second)); secondAddress.DisplacementDelta = 4; this.assembly.MOV (R32.EAX, firstAddress); this.assembly.MOV (R32.EDX, secondAddress); this.assembly.CMP (R32.EAX, R32.EDX); RelationalTypeCMP (instruction.RelationalType, okLabel, errorLabel); this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (first))); this.assembly.MOV (R32.EDX, new DWordMemory (this.GetAddress (second))); this.assembly.CMP (R32.EAX, R32.EDX); RelationalTypeCMP (instruction.RelationalType, okLabel); break; default: throw new NotImplementedEngineException ("ConditionCheck for " + first.InternalType.ToString() + " and " + second.InternalType.ToString()); } assembly.LABEL (errorLabel); this.assembly.XOR (R32.ECX, R32.ECX); this.assembly.JMP (endLabel); assembly.LABEL (okLabel); this.assembly.XOR (R32.ECX, R32.ECX); this.assembly.INC (R32.ECX); this.assembly.LABEL (endLabel); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.ECX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.ECX); }
/// <summary> /// Implements the 'conv' family of IL instructions, which handle conversions between primitive data types. /// </summary> private void Convert (IR.Instructions.Convert instruction) { IR.Operands.Register assignee = instruction.Def as IR.Operands.Register; IR.Operands.Register value = instruction.Use [0] as IR.Operands.Register; switch (value.InternalType) { case InternalType.M: case InternalType.I: case InternalType.U: case InternalType.I4: switch (instruction.ConvertType) { case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_I1: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_U1: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); this.assembly.AND (R32.EAX, (uint) 0xFF); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_I2: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_U2: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); this.assembly.AND (R32.EAX, (uint) 0xFFFF); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_I: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_I4: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_U: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_U4: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_I8: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_U8: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); Memory memory = this.GetAddress (assignee); DWordMemory low = new DWordMemory (memory); this.assembly.MOV (low, R32.EAX); DWordMemory high = new DWordMemory (memory); high.DisplacementDelta = 4; this.assembly.XOR (R32.EAX, R32.EAX); this.assembly.MOV (high, R32.EAX); break; default: throw new NotImplementedEngineException ("The conversion from " + value.InternalType + " to " + instruction.ConvertType + " is not yet supported."); } break; case InternalType.I8: switch (instruction.ConvertType) { case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_I: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_U: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_I4: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_U4: this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_I1: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_U1: this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); this.assembly.AND (R32.EAX, (uint) 0xFF); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_Ovf_I: case SharpOS.AOT.IR.Instructions.Convert.Type.Conv_Ovf_I4: string exceptLabel = this.assembly.GetCMPLabel; string okLabel = this.assembly.GetCMPLabel; DWordMemory upper = new DWordMemory (this.GetAddress (value)); upper.DisplacementDelta = 4; // Check if it will overflow this.assembly.MOV (R32.EAX, upper); this.assembly.CMP (R32.EAX, 0); this.assembly.JNE (exceptLabel); // Handle the conversion this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); this.assembly.JMP (okLabel); // Conversion overflows, throw exception. this.assembly.LABEL (exceptLabel); this.assembly.CALL (this.assembly.Engine.OverflowHandler.AssemblyLabel); this.assembly.LABEL (okLabel); break; default: throw new NotImplementedEngineException ("The conversion from " + value.InternalType + " to " + instruction.ConvertType + " is not yet supported."); } break; default: throw new NotImplementedEngineException ("Convert not supported from value type InternalType." + value.InternalType); } }
private void PushOperand(Operand operand) { if (operand is IntConstant) { Int32 value = System.Convert.ToInt32((operand as IntConstant).Value); assembly.PUSH((UInt32)value); } else if (operand is LongConstant) { Int64 value = System.Convert.ToInt64((operand as LongConstant).Value); assembly.PUSH((UInt32)(value >> 32)); assembly.PUSH((UInt32)(value & 0xFFFFFFFF)); } else if (operand is IR.Operands.Register) { IR.Operands.Register identifier = operand as IR.Operands.Register; switch (identifier.InternalType) { case InternalType.SZArray: case InternalType.Array: case InternalType.I: case InternalType.O: case InternalType.M: case InternalType.I4: if (identifier.IsRegisterSet) { this.assembly.PUSH(Assembly.GetRegister(identifier.Register)); } else { this.assembly.PUSH(new DWordMemory(this.GetAddress(identifier))); } break; case InternalType.I8: Memory memory = this.GetAddress(identifier); DWordMemory high = new DWordMemory(memory); high.DisplacementDelta = 4; assembly.PUSH(new DWordMemory(high)); DWordMemory low = new DWordMemory(memory); assembly.PUSH(low); break; case InternalType.ValueType: int size = this.method.Engine.GetTypeSize(identifier.Type.ToString()); uint pushSize = (uint)size; if (pushSize % 4 != 0) { pushSize = (uint)(((pushSize / this.assembly.IntSize) + 1) * this.assembly.IntSize); } this.assembly.SUB(R32.ESP, pushSize); this.assembly.PUSH(R32.ESI); this.assembly.PUSH(R32.EDI); this.assembly.PUSH(R32.ECX); this.assembly.LEA(R32.ESI, new DWordMemory(this.GetAddress(identifier))); // The 3 push above changed the ESP so we need a LEA = ESP + 12 this.assembly.LEA(R32.EDI, new Memory(null, R32.ESP, null, 0, 12)); this.assembly.MOV(R32.ECX, (uint)size); this.assembly.CLD(); this.assembly.REP(); this.assembly.MOVSB(); this.assembly.POP(R32.ECX); this.assembly.POP(R32.EDI); this.assembly.POP(R32.ESI); break; default: throw new NotImplementedEngineException("'" + operand + "' is not supported."); } } else { throw new NotImplementedEngineException("'" + operand + "' is not supported."); } }
/// <summary> /// SHRD mem32,reg32,CL /// </summary> public static void SHRD___CL (DWordMemory target, R32Type source) { }
/// <summary> /// MUL mem32 /// </summary> public static void MUL (DWordMemory target) { }
/// <summary> /// MOV segreg,mem32 /// </summary> public static void MOV (SegType target, DWordMemory source) { }
/// <summary> /// MOV mem32,segreg /// </summary> public static void MOV (DWordMemory target, SegType source) { }
/// <summary> /// JMP FAR mem32 /// </summary> public static void JMP_FAR (DWordMemory target) { }
/// <summary> /// INC mem32 /// </summary> public static void INC (DWordMemory target) { }
/// <summary> /// IMUL reg32,mem32,imm32 /// </summary> public static void IMUL (R32Type target, DWordMemory source, UInt32 value) { }
/// <summary> /// IDIV mem32 /// </summary> public static void IDIV (DWordMemory target) { }
/// <summary> /// FSUBR mem32 /// </summary> public static void FSUBR (DWordMemory target) { }
/// <summary> /// SHRD mem32,reg32,imm8 /// </summary> public static void SHRD (DWordMemory target, R32Type source, Byte value) { }
/// <summary> /// NOT mem32 /// </summary> public static void NOT (DWordMemory target) { }
/// <summary> /// SUB mem32,reg32 /// </summary> public static void SUB (DWordMemory target, R32Type source) { }
/// <summary> /// POP mem32 /// </summary> public static void POP (DWordMemory target) { }
/// <summary> /// PUSH mem32 /// </summary> public static void PUSH (DWordMemory target) { }
/// <summary> /// ROL mem32,CL /// </summary> public static void ROL__CL (DWordMemory target) { }
/// <summary> /// Implements the 'branch' family of IL instructions. /// </summary> private void Branch (IR.Instructions.Branch instruction) { string okLabel = this.GetLabel (instruction.Block.Outs [0]); string errorLabel = this.GetLabel (instruction.Block.Outs [1]); IR.Operands.Register first = instruction.Use [0] as IR.Operands.Register; IR.Operands.Register second = instruction.Use [1] as IR.Operands.Register; switch (first.InternalType) { case InternalType.I: case InternalType.O: case InternalType.M: case InternalType.I4: case InternalType.SZArray: if (first.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (first.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (first))); if (second.IsRegisterSet) this.assembly.MOV (R32.EDX, Assembly.GetRegister (second.Register)); else this.assembly.MOV (R32.EDX, new DWordMemory (this.GetAddress (second))); this.assembly.CMP (R32.EAX, R32.EDX); this.RelationalTypeCMP (instruction.RelationalType, okLabel); break; case InternalType.I8: DWordMemory firstAddress = new DWordMemory (this.GetAddress (first)); firstAddress.DisplacementDelta = 4; DWordMemory secondAddress = new DWordMemory (this.GetAddress (second)); secondAddress.DisplacementDelta = 4; this.assembly.MOV (R32.EAX, firstAddress); this.assembly.MOV (R32.EDX, secondAddress); this.assembly.CMP (R32.EAX, R32.EDX); RelationalTypeCMP (instruction.RelationalType, okLabel, errorLabel); this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (first))); this.assembly.MOV (R32.EDX, new DWordMemory (this.GetAddress (second))); this.assembly.CMP (R32.EAX, R32.EDX); RelationalTypeCMP (instruction.RelationalType, okLabel); break; default: throw new NotImplementedEngineException ("Branch not supported for InternalType." + first.InternalType); } }
/// <summary> /// SBB reg32,mem32 /// </summary> public static void SBB (R32Type target, DWordMemory source) { }
/// <summary> /// Implements the 'dup' IR instruction, which duplicates the top value on the evaluation stack. /// </summary> private void Dup (IR.Instructions.Dup instruction) { IR.Operands.Register assignee = instruction.Def as IR.Operands.Register; IR.Operands.Register value = instruction.Use [0] as IR.Operands.Register; switch (assignee.InternalType) { case InternalType.I: case InternalType.O: case InternalType.M: case InternalType.I4: case InternalType.SZArray: case InternalType.Array: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case InternalType.I8: Memory sourceMemory = this.GetAddress (value); DWordMemory source = new DWordMemory (sourceMemory); source.DisplacementDelta = 4; Memory destinationMemory = this.GetAddress (assignee); DWordMemory destination = new DWordMemory (destinationMemory); destination.DisplacementDelta = 4; this.assembly.MOV (R32.EAX, source); this.assembly.MOV (destination, R32.EAX); this.assembly.MOV (R32.EAX, new DWordMemory (sourceMemory)); this.assembly.MOV (new DWordMemory (destinationMemory), R32.EAX); break; default: throw new NotImplementedEngineException ("Dup not supported for InternalType." + assignee.InternalType); } }
/// <summary> /// SBB mem32,imm32 /// </summary> public static void SBB (DWordMemory target, UInt32 source) { }
/// <summary> /// Implements the 'shr' IL instruction, which pops two values from the stack, /// right-bit-shifts the first by the amount defined in the second, and pushes /// the result. /// </summary> private void Shr (IR.Instructions.Shr instruction) { IR.Operands.Register assignee = instruction.Def as IR.Operands.Register; IR.Operands.Register first = instruction.Use [0] as IR.Operands.Register; IR.Operands.Register second = instruction.Use [1] as IR.Operands.Register; switch (assignee.InternalType) { case InternalType.I: case InternalType.I4: if (first.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (first.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (first))); if (second.IsRegisterSet) this.assembly.MOV (R32.ECX, Assembly.GetRegister (second.Register)); else this.assembly.MOV (R32.ECX, new DWordMemory (this.GetAddress (second))); this.assembly.AND (R32.ECX, (uint) 0xFF); if (instruction.ShrType == IR.Instructions.Shr.Type.SHR) this.assembly.SAR__CL (R32.EAX); else if (instruction.ShrType == IR.Instructions.Shr.Type.SHRUnsigned) this.assembly.SHR__CL (R32.EAX); else throw new NotImplementedEngineException ("Shr not supported for Shr.Type." + instruction.ShrType); if (assignee.IsRegisterSet) this.assembly.MOV (Assembly.GetRegister (assignee.Register), R32.EAX); else this.assembly.MOV (new DWordMemory (this.GetAddress (assignee)), R32.EAX); break; case InternalType.I8: Memory firstMemory = this.GetAddress (first); DWordMemory high = new DWordMemory (firstMemory); high.DisplacementDelta = 4; DWordMemory low = new DWordMemory (firstMemory); if (second.IsRegisterSet) this.assembly.PUSH (Assembly.GetRegister (second.Register)); else this.assembly.PUSH (new DWordMemory (this.GetAddress (second))); this.assembly.PUSH (high); this.assembly.PUSH (low); if (instruction.ShrType == IR.Instructions.Shr.Type.SHR) this.assembly.CALL (Assembly.HELPER_LSAR); else if (instruction.ShrType == IR.Instructions.Shr.Type.SHRUnsigned) this.assembly.CALL (Assembly.HELPER_LSHR); else throw new NotImplementedEngineException ("Shr not supported for Shr.Type." + instruction.ShrType); this.assembly.ADD (R32.ESP, 12); Memory assigneeMemory = this.GetAddress (assignee); this.assembly.MOV (new DWordMemory (assigneeMemory), R32.EAX); assigneeMemory.DisplacementDelta = 4; this.assembly.MOV (new DWordMemory (assigneeMemory), R32.EDX); break; default: throw new NotImplementedEngineException ("Shr not supported for InternalType." + assignee.InternalType); } }
/// <summary> /// SHR mem32,CL /// </summary> public static void SHR__CL (DWordMemory target) { }
/// <summary> /// Implements the 'ret' IL instruction. /// </summary> /// <param name="block">The block.</param> /// <param name="instruction">The instruction.</param> private void Return (SharpOS.AOT.IR.Instructions.Return instruction) { if (instruction.Use != null) { IR.Operands.Register value = instruction.Use [0] as IR.Operands.Register; switch (value.InternalType) { case InternalType.I: case InternalType.M: case InternalType.O: case InternalType.I4: case InternalType.SZArray: case InternalType.Array: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); break; case InternalType.I8: Memory assigneeMemory = this.GetAddress (value); DWordMemory low = new DWordMemory (assigneeMemory); this.assembly.MOV (R32.EAX, low); DWordMemory high = new DWordMemory (assigneeMemory); high.DisplacementDelta = 4; this.assembly.MOV (R32.EDX, high); break; case InternalType.ValueType: int size = this.method.Engine.GetTypeSize (instruction.Block.Method.ReturnType.TypeFullName, 4) / 4; this.assembly.PUSH (R32.ECX); this.assembly.PUSH (R32.ESI); this.assembly.PUSH (R32.EDI); if (value.IsRegisterSet) this.assembly.MOV (R32.ESI, Assembly.GetRegister (value.Register)); else this.assembly.LEA (R32.ESI, new DWordMemory (this.GetAddress (value))); this.assembly.MOV (R32.EDI, new DWordMemory (null, R32.EBP, null, 0, 8)); this.assembly.MOV (R32.ECX, (uint) size); this.assembly.CLD (); this.assembly.REP (); this.assembly.MOVSD (); this.assembly.POP (R32.EDI); this.assembly.POP (R32.ESI); this.assembly.POP (R32.ECX); break; default: throw new NotImplementedEngineException ("'" + instruction + "' is not supported."); } } assembly.JMP (method.MethodFullName + " exit"); }
/// <summary> /// BTC mem32,imm8 /// </summary> public static void BTC (DWordMemory target, Byte source) { }
/// <summary> /// Common implementations which pop a value from the IL evaluation stack and save it in another means /// of storage (such as stloc, stind, starg). /// </summary> private void Save (Class _class, InternalType destinationType, Memory memory, IR.Operands.Register value) { switch (destinationType) { case InternalType.I1: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); this.assembly.MOV (new ByteMemory (memory), R8.AL); break; case InternalType.U1: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); this.assembly.MOV (new ByteMemory (memory), R8.AL); break; case InternalType.I2: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); this.assembly.MOV (new WordMemory (memory), R16.AX); break; case InternalType.U2: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); this.assembly.MOV (new WordMemory (memory), R16.AX); break; case InternalType.I4: case InternalType.U4: case InternalType.I: case InternalType.U: case InternalType.O: case InternalType.SZArray: case InternalType.Array: if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); this.assembly.MOV (new DWordMemory (memory), R32.EAX); break; case InternalType.I8: case InternalType.U8: Memory source = this.GetAddress (value); source.DisplacementDelta = 4; DWordMemory destination = new DWordMemory (memory); destination.DisplacementDelta = 4; this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); this.assembly.MOV (new DWordMemory (memory), R32.EAX); this.assembly.MOV (R32.EAX, new DWordMemory (source)); this.assembly.MOV (new DWordMemory (destination), R32.EAX); break; case InternalType.ValueType: uint size = (uint) this.method.Engine.GetTypeSize (_class.TypeFullName, 4); if (size == 4) { if (value.IsRegisterSet) this.assembly.MOV (R32.EAX, Assembly.GetRegister (value.Register)); else this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (value))); this.assembly.MOV (new DWordMemory (memory), R32.EAX); } else { this.assembly.PUSH (R32.ECX); this.assembly.PUSH (R32.ESI); this.assembly.PUSH (R32.EDI); if (value.IsRegisterSet) this.assembly.MOV (R32.ESI, Assembly.GetRegister (value.Register)); else this.assembly.LEA (R32.ESI, new DWordMemory (this.GetAddress (value))); this.assembly.LEA (R32.EDI, new DWordMemory (memory)); this.assembly.MOV (R32.ECX, size); this.assembly.CLD (); this.assembly.REP (); this.assembly.MOVSB (); this.assembly.POP (R32.EDI); this.assembly.POP (R32.ESI); this.assembly.POP (R32.ECX); } break; case InternalType.R4: case InternalType.R8: case InternalType.F: case InternalType.M: case InternalType.TypedReference: default: throw new NotImplementedEngineException ("Save not supported for InternalType." + destinationType); } }
/// <summary> /// FSTP mem32 /// </summary> public static void FSTP (DWordMemory target) { }