/// <summary> /// Create the stack after this bytecode has executed, based on StackBefore. /// </summary> public StackSlot[] CreateNewStack() { switch (Code) { case AstCode.Dup_x1: return(StackSlot.ModifyStackDupX1(StackBefore)); case AstCode.Dup_x2: return(StackSlot.ModifyStackDupX2(StackBefore)); case AstCode.Dup2: return(StackSlot.ModifyStackDup2(StackBefore)); case AstCode.Dup2_x1: return(StackSlot.ModifyStackDup2X1(StackBefore)); case AstCode.Dup2_x2: return(StackSlot.ModifyStackDup2X2(StackBefore)); case AstCode.Swap: return(StackSlot.ModifyStackSwap(StackBefore)); case AstCode.Pop2: return(StackSlot.ModifyStackPop2(StackBefore)); default: return(StackSlot.ModifyStack(StackBefore, PopCount ?? StackBefore.Length, PushCount, this)); } }
public StackSlot SpillVariable(IRVariable var) { var slot = new StackSlot(SpillOffset++, var); spillVars[var] = slot; return(slot); }
public static void exec_try_write_prop(StackFrame frame,OpStep step,RunTimeScope scope) { StackSlot slot = (StackSlot)((StackSlotAccessor)step.arg1).getSlot(scope,frame); if (slot.stackObjects.propGetSet != null) { OpAssigning._doPropAssigning(slot.stackObjects.propGetSet,frame,step,frame.player,scope, slot.stackObjects.propBindObj , slot.getValue() , slot ); } else if (slot.stackObjects._temp_try_write_setthisitem != null) { SetThisItemSlot sslot = (SetThisItemSlot)slot.stackObjects._temp_try_write_setthisitem; slot.stackObjects._temp_try_write_setthisitem = null; OpAssigning._doSetThisItem( sslot.bindObj,sslot.set_this_item, slot.getValue(), sslot.setindex, slot,frame,step ); } else { //frame.endStep(step); frame.endStepNoError(); } }
public static StackSlot[] ModifyStackDup2(StackSlot[] stack) { if (stack[stack.Length - 1].IsCategory2) { // Form 2 var value = stack[stack.Length - 1].Definitions; var newStack = new StackSlot[stack.Length - 1 + 2]; Array.Copy(stack, newStack, stack.Length - 1); newStack[newStack.Length - 2] = new StackSlot(value, null); newStack[newStack.Length - 1] = new StackSlot(value, null); return newStack; } else { // Form 1 var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var newStack = new StackSlot[stack.Length - 2 + 4]; Array.Copy(stack, newStack, stack.Length - 2); newStack[newStack.Length - 4] = new StackSlot(value2, null); newStack[newStack.Length - 3] = new StackSlot(value1, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return newStack; } }
public static StackSlot[] ModifyStackDup2(StackSlot[] stack) { if (stack[stack.Length - 1].IsCategory2) { // Form 2 var value = stack[stack.Length - 1].Definitions; var newStack = new StackSlot[stack.Length - 1 + 2]; Array.Copy(stack, newStack, stack.Length - 1); newStack[newStack.Length - 2] = new StackSlot(value, null); newStack[newStack.Length - 1] = new StackSlot(value, null); return(newStack); } else { // Form 1 var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var newStack = new StackSlot[stack.Length - 2 + 4]; Array.Copy(stack, newStack, stack.Length - 2); newStack[newStack.Length - 4] = new StackSlot(value2, null); newStack[newStack.Length - 3] = new StackSlot(value1, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return(newStack); } }
void IBlockCallBack.call(object args) { #if DEBUG clear_para_slot(invokerFrame,onstackparametercount); #else { int count = onstackparametercount; while (count > 0) { --count; StackSlot slot = invokerFrame.stack[invokerFrame.baseBottomSlotIndex + (--invokerFrame.call_parameter_slotCount)]; if (slot.refPropChanged) { slot.refPropChanged = false; slot.stackObjects = StackSlot.StackObjects.EMPTY; if (slot.needclear) { slot.linktarget = null; slot._cache_arraySlot.clear(); slot._cache_vectorSlot.clear(); slot._cache_prototypeSlot.clear(); slot._cache_setthisslot.clear(); slot._linkObjCache.clearRefObj(); slot._functionValue.Clear(); slot._functon_result.Clear(); slot.needclear = false; } slot.store[StackSlot.COMMREFTYPEOBJ] = ASBinCode.rtData.rtNull.nullptr; } slot.index = (int)RunTimeDataType.unknown; } } #endif onstackparametercount = 0; invokerFrame.endStepNoError(); //release(); //人肉内联release if (!hasReleased) { hasReleased = true; callbacker = null; CallFuncHeap = null; toCallFunc = null; returnSlot = null; _tempSlot = null; invokerFrame = null; token = null; tag = null; function.Clear(); player.funcCallerPool.ret(this); } }
public static void exec_delete(StackFrame frame, OpStep step, RunTimeScope scope) { { StackSlot slot = (StackSlot)((StackSlotAccessor)step.arg1).getSlot(scope, frame); var ls = slot.getLinkSlot(); if (ls is DynamicPropertySlot) { DynamicPropertySlot link = (DynamicPropertySlot)ls; if (link._canDelete) { ((ASBinCode.rtti.DynamicObject)link.obj.value).deleteProperty(link._propname); } else { if (link.backup != null) { link.directSet(link.backup); } } } else if (ls is DictionarySlot) { DictionarySlot link = (DictionarySlot)ls; ((ASBinCode.rtti.DictionaryObject)link.obj.value).RemoveKey(link._key); } else if (ls is OpAccess_Dot.arraySlot) //(slot.fromArray != null) { //slot.directSet(rtUndefined.undefined); //bool success; //slot.assign(rtUndefined.undefined,out success); ((OpAccess_Dot.arraySlot)ls).delete(); //slot.fromArray.innerArray[slot.fromArrayIndex] = rtUndefined.undefined; } else if (ls is OpAccess_Dot.prototypeSlot) { //原型链对象,不可删除 } else if (ls is OpVector.vectorSLot) { //数组链接,跳过 } else { frame.throwError( step.token, 0, "动态属性才能被delete" ); } slot.linkTo(null); frame.endStep(step); } }
public static void _doSetThisItem(ASBinCode.rtData.rtObjectBase thisObj, RunTimeValueBase v,RunTimeValueBase index,StackSlot slot,StackFrame frame,OpStep step ) { //***读取setter*** RunTimeValueBase func; func = ((MethodGetterBase)thisObj.value._class.set_this_item.bindField).getMethod( thisObj ); //***调用设置器*** var funCaller = frame.player.funcCallerPool.create(frame,step.token); funCaller.SetFunction((ASBinCode.rtData.rtFunction)func); ((ASBinCode.rtData.rtFunction)func).Clear(); funCaller.loadDefineFromFunction(); if (!funCaller.createParaScope()) { return; } //funCaller.releaseAfterCall = true; bool success; funCaller.pushParameter(v,0,out success); if (!success) { frame.endStep(step); return; } funCaller.pushParameter(index,1,out success); if (!success) { frame.endStep(step); return; } funCaller._tempSlot = frame._tempSlot1; funCaller.returnSlot = frame._tempSlot1; BlockCallBackBase cb = frame.player.blockCallBackPool.create(); cb.setCallBacker(_setthisitem_callbacker); cb.step = step; cb.args = frame; funCaller.callbacker = cb; funCaller.call(); return; }
public static StackSlot[] ModifyStack(StackSlot[] stack, int popCount, int pushCount, ByteCode pushDefinition) { var newStack = new StackSlot[stack.Length - popCount + pushCount]; Array.Copy(stack, newStack, stack.Length - popCount); for (int i = stack.Length - popCount; i < newStack.Length; i++) { newStack[i] = new StackSlot(new[] { pushDefinition }, null); } return newStack; }
public static StackSlot[] ModifyStack(StackSlot[] stack, int popCount, int pushCount, ByteCode pushDefinition) { StackSlot[] newStack = new StackSlot[stack.Length - popCount + pushCount]; Array.Copy(stack, newStack, stack.Length - popCount); for (int i = stack.Length - popCount; i < newStack.Length; i++) { newStack[i] = new StackSlot(new[] { pushDefinition }, null); } return(newStack); }
public static StackSlot[] ModifyStackSwap(StackSlot[] stack) { var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var newStack = new StackSlot[stack.Length - 2 + 2]; Array.Copy(stack, newStack, stack.Length - 2); newStack[newStack.Length - 2] = new StackSlot(value1, null); newStack[newStack.Length - 1] = new StackSlot(value2, null); return(newStack); }
private static void clear_para_slot(StackFrame invokerFrame,int count) { while (count > 0) { #if DEBUG int i = invokerFrame.baseBottomSlotIndex + invokerFrame.call_parameter_slotCount; //invokerFrame.offset + invokerFrame.block.totalRegisters + 1 + 1 + invokerFrame.call_parameter_slotCount; --invokerFrame.call_parameter_slotCount; --i; --count; invokerFrame.stack[i].clear(); #else --count; StackSlot slot = invokerFrame.stack[invokerFrame.baseBottomSlotIndex + (--invokerFrame.call_parameter_slotCount)]; if (slot.refPropChanged) { slot.refPropChanged = false; slot.stackObjects = StackSlot.StackObjects.EMPTY; if (slot.needclear) { slot.linktarget = null; slot._cache_arraySlot.clear(); slot._cache_vectorSlot.clear(); slot._cache_prototypeSlot.clear(); slot._cache_setthisslot.clear(); slot._linkObjCache.clearRefObj(); slot._functionValue.Clear(); slot._functon_result.Clear(); slot.needclear = false; } slot.store[StackSlot.COMMREFTYPEOBJ] = ASBinCode.rtData.rtNull.nullptr; } slot.index = (int)RunTimeDataType.unknown; #endif } //if (invokerFrame.call_parameter_slotCount > 0) //{ // //**清理** // for (int i = invokerFrame.offset + invokerFrame.block.totalRegisters + 1 + 1; // i < invokerFrame.offset + invokerFrame.block.totalRegisters + 1 + 1 + invokerFrame.call_parameter_slotCount // ; i++) // { // invokerFrame.stack[i].clear(); // } // invokerFrame.call_parameter_slotCount = 0; //} }
public static StackSlot[] ModifyStackDupX1(StackSlot[] stack) { var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var newStack = new StackSlot[stack.Length - 2 + 3]; Array.Copy(stack, newStack, stack.Length - 2); newStack[newStack.Length - 3] = new StackSlot(value1, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return newStack; }
public void Initialize() { var blocks = transformer.RootScope.GetBasicBlocks().Cast <BasicBlock <IRInstrList> >().ToList(); liveness = LivenessAnalysis.ComputeLiveness(blocks); var stackVars = new HashSet <IRVariable>(); foreach (var blockLiveness in liveness) { foreach (var instr in blockLiveness.Key.Content) { if (instr.OpCode != IROpCode.__LEA) { continue; } var variable = (IRVariable)instr.Operand2; if (variable.VariableType != IRVariableType.Argument) { stackVars.Add(variable); } } stackVars.UnionWith(blockLiveness.Value.OutLive); } // [BP - 2] = last argument // [BP - 1] = return address // [BP ] = old BP // [BP + 1] = first local var offset = 1; globalVars = stackVars.ToDictionary(var => var, var => new StackSlot(offset++, var)); baseOffset = offset; LocalSize = baseOffset - 1; offset = -2; var parameters = transformer.Context.GetParameters(); for (var i = parameters.Length - 1; i >= 0; i--) { var paramVar = parameters[i]; globalVars[paramVar] = new StackSlot(offset--, paramVar); } allocation = globalVars.ToDictionary(pair => pair.Key, pair => (object)pair.Value); }
public static StackSlot[] ModifyStack(StackSlot[] stack, int popCount, int pushCount, ByteCode pushDefinition) { //wicky.patch.start: get around error if (stack.Length < popCount) { return(new StackSlot[0]); } //wicky.patch.end StackSlot[] newStack = new StackSlot[stack.Length - popCount + pushCount]; Array.Copy(stack, newStack, stack.Length - popCount); for (int i = stack.Length - popCount; i < newStack.Length; i++) { newStack[i] = new StackSlot(new [] { pushDefinition }, null); } return(newStack); }
public override string ToString() { StringBuilder sb = new StringBuilder(); if (StackSlot != null) { sb.AppendLine($"\t\t\tStack:"); sb.AppendLine(StackSlot.ToString()); } else { sb.AppendLine($"\t\t\tRegisterNumber: {RegisterNumber}"); } sb.AppendLine($"\t\t\tFlags: {Flags}"); return(sb.ToString()); }
public override string ToString() { StringBuilder sb = new StringBuilder(); string tab3 = new string(' ', 12); if (StackSlot != null) { sb.AppendLine($"{tab3}Stack:"); sb.AppendLine(StackSlot.ToString()); } else { sb.AppendLine($"{tab3}RegisterNumber: {RegisterNumber}"); } sb.AppendLine($"{tab3}Flags: {Flags}"); return(sb.ToString()); }
public override GcSlotFlags WriteTo(StringBuilder sb, Machine machine, GcSlotFlags prevFlags) { if (prevFlags != Flags) { sb.Append(Flags.ToString()); sb.Append(' '); } if (StackSlot != null) { sb.Append(StackSlot.ToString()); } else { sb.Append(GetRegisterName(RegisterNumber, machine)); } return(Flags); }
public static void exec_link(StackFrame frame, OpStep step, RunTimeScope scope) { StackSlot l = (StackSlot)step.reg.getSlot(scope, frame); int classid = ((ASBinCode.rtData.rtInt)step.arg2.getValue(scope, frame)).value; var outscope = frame.player.outpackage_runtimescope[classid]; SLOT outpackagescopeslot = ((VariableBase)step.arg1).getSlot(outscope,null); StackSlotAccessor register = (StackSlotAccessor)step.reg; if (register._isassigntarget || register._hasUnaryOrShuffixOrDelete) { l.linkTo(outpackagescopeslot); } else { l.directSet(outpackagescopeslot.getValue()); } frame.endStep(step); }
public static StackSlot[] ModifyStackDup2X1(StackSlot[] stack) { if (stack[stack.Length - 1].IsCategory2) { // Form 2 return(ModifyStackDupX1(stack)); } else { // Form 1 var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var value3 = stack[stack.Length - 3].Definitions; var newStack = new StackSlot[stack.Length - 3 + 5]; Array.Copy(stack, newStack, stack.Length - 3); newStack[newStack.Length - 5] = new StackSlot(value2, null); newStack[newStack.Length - 4] = new StackSlot(value1, null); newStack[newStack.Length - 3] = new StackSlot(value3, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return(newStack); } }
private static ASBinCode.rtti.Object createObject(CSWC swc,Class cls,InstanceCreator creator, out ASBinCode.rtData.rtObjectBase rtObjectBase, out ASBinCode.rtData.rtObjectBase linkrtobj, out string errinfo ) { ASBinCode.rtti.Object obj = null;// = new ASBinCode.rtti.Object(cls); rtObjectBase = null; linkrtobj = null; errinfo = null; if (cls.isLink_System) { if (creator != null) { StackSlot stackSlot = creator.objectStoreToSlot as StackSlot; if (stackSlot != null) { rtObjectBase = stackSlot.getStackCacheObject(cls); return(rtObjectBase.value); } } var func = (NativeFunctionBase)swc.class_Creator[cls]; string err; int no; ASBinCode.rtData.rtObjectBase rtObj = func.execute(null,null,cls,out err,out no) as ASBinCode.rtData.rtObjectBase; linkrtobj = rtObj; if (rtObj == null) { errinfo = cls.ToString() + " create linksystem object failed"; return(null); } else { return(rtObj.value); } } else if (cls.isCrossExtend) { var scls = cls.super; while (!scls.isLink_System) { scls = scls.super; } var cextend = scls.staticClass.linkObjCreator; var func = swc.getNativeFunction(((ClassMethodGetter)cextend.bindField).functionId); if (func == null) { errinfo = cls.ToString() + " create crossextend object failed, creator function not found"; return(null); } string err; int no; ASBinCode.rtData.rtObjectBase rtObj = func.execute(null,null,cls,out err,out no) as ASBinCode.rtData.rtObjectBase; linkrtobj = rtObj; if (rtObj == null) { errinfo = cls.ToString() + " create crossextend object failed"; return(null); } else { LinkSystemObject lo = (LinkSystemObject)rtObj.value; return(lo); } } else if ( swc.DictionaryClass != null && ClassMemberFinder.isInherits(cls,swc.DictionaryClass)) { obj = new DictionaryObject(cls); } else if (cls.dynamic) { if (cls.isUnmanaged) { obj = new HostedDynamicObject(cls); } else { obj = new DynamicObject(cls); } } else if (cls.isUnmanaged) { obj = new HostedObject(cls); } else { obj = new ASBinCode.rtti.Object(cls); } return(obj); }
public static StackSlot[] ModifyStackDup2X2(StackSlot[] stack) { var s1 = stack[stack.Length - 1]; var s2 = stack[stack.Length - 2]; if (s1.IsCategory2 && s2.IsCategory2) { // Form 4 return(ModifyStackDupX1(stack)); } var s3 = stack[stack.Length - 3]; if (s3.IsCategory2 && !s1.IsCategory2 && !s2.IsCategory2) { // Form 3 var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var value3 = stack[stack.Length - 3].Definitions; var newStack = new StackSlot[stack.Length - 3 + 5]; Array.Copy(stack, newStack, stack.Length - 3); newStack[newStack.Length - 5] = new StackSlot(value2, null); newStack[newStack.Length - 4] = new StackSlot(value1, null); newStack[newStack.Length - 3] = new StackSlot(value3, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return(newStack); } if (s1.IsCategory2) { // Form 2 var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var value3 = stack[stack.Length - 3].Definitions; var newStack = new StackSlot[stack.Length - 3 + 4]; Array.Copy(stack, newStack, stack.Length - 3); newStack[newStack.Length - 4] = new StackSlot(value1, null); newStack[newStack.Length - 3] = new StackSlot(value3, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return(newStack); } else { var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var value3 = stack[stack.Length - 3].Definitions; var value4 = stack[stack.Length - 4].Definitions; var newStack = new StackSlot[stack.Length - 4 + 6]; Array.Copy(stack, newStack, stack.Length - 4); newStack[newStack.Length - 6] = new StackSlot(value2, null); newStack[newStack.Length - 5] = new StackSlot(value1, null); newStack[newStack.Length - 4] = new StackSlot(value4, null); newStack[newStack.Length - 3] = new StackSlot(value3, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return(newStack); } }
/// <summary> /// Update the state of the given branch targets (of the given bytecode). /// Add modified branch targets to the given agenda. /// </summary> private static void UpdateBranchTarget(ByteCode byteCode, ByteCode branchTarget, bool canShareNewState, StackSlot[] newStack, VariableSlot[] newVariableState, Stack <ByteCode> agenda) { if ((branchTarget.StackBefore == null) && (branchTarget.VariablesBefore == null)) { // Branch target has not been processed at all if (canShareNewState) { branchTarget.StackBefore = newStack; branchTarget.VariablesBefore = newVariableState; } else { // Do not share data for several bytecodes branchTarget.StackBefore = StackSlot.ModifyStack(newStack, 0, 0, null); branchTarget.VariablesBefore = VariableSlot.CloneVariableState(newVariableState); } agenda.Push(branchTarget); return; } // If we get here, the branch target has been processed before. // See the the stack size is the same and merge the state where needed. if ((branchTarget.StackBefore == null) || (branchTarget.StackBefore.Length != newStack.Length)) { throw new Exception("Inconsistent stack size at " + byteCode.Name); } // Be careful not to change our new data - it might be reused for several branch targets. // In general, be careful that two bytecodes never share data structures. var modified = false; // Merge stacks - modify the target for (var i = 0; i < newStack.Length; i++) { var oldDefs = branchTarget.StackBefore[i].Definitions; var newDefs = oldDefs.Union(newStack[i].Definitions); if (newDefs.Length > oldDefs.Length) { branchTarget.StackBefore[i] = new StackSlot(newDefs, null); modified = true; } } // Merge variables - modify the target for (var i = 0; i < newVariableState.Length; i++) { var oldSlot = branchTarget.VariablesBefore[i]; var newSlot = newVariableState[i]; if (oldSlot.UnknownDefinition) { continue; } if (newSlot.UnknownDefinition) { branchTarget.VariablesBefore[i] = newSlot; modified = true; } else { var oldDefs = oldSlot.Definitions; var newDefs = oldDefs.Union(newSlot.Definitions); if (newDefs.Length > oldDefs.Length) { branchTarget.VariablesBefore[i] = new VariableSlot(newDefs, false); modified = true; } } } if (modified) { agenda.Push(branchTarget); } }
List <ByteCode> StackAnalysis(MethodDefinition methodDef) { Dictionary <Instruction, ByteCode> instrToByteCode = new Dictionary <Instruction, ByteCode>(); // Create temporary structure for the stack analysis List <ByteCode> body = new List <ByteCode>(methodDef.Body.Instructions.Count); List <Instruction> prefixes = null; foreach (Instruction inst in methodDef.Body.Instructions) { if (inst.OpCode.OpCodeType == OpCodeType.Prefix) { if (prefixes == null) { prefixes = new List <Instruction>(1); } prefixes.Add(inst); continue; } ILCode code = (ILCode)inst.OpCode.Code; object operand = inst.Operand; ILCodeUtil.ExpandMacro(ref code, ref operand, methodDef.Body); ByteCode byteCode = new ByteCode() { Offset = inst.Offset, EndOffset = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize, Code = code, Operand = operand, PopCount = inst.GetPopDelta(methodDef), PushCount = inst.GetPushDelta() }; if (prefixes != null) { instrToByteCode[prefixes[0]] = byteCode; byteCode.Offset = prefixes[0].Offset; byteCode.Prefixes = prefixes.ToArray(); prefixes = null; } else { instrToByteCode[inst] = byteCode; } body.Add(byteCode); } for (int i = 0; i < body.Count - 1; i++) { body[i].Next = body[i + 1]; } Stack <ByteCode> agenda = new Stack <ByteCode>(); int varCount = methodDef.Body.Variables.Count; var exceptionHandlerStarts = new HashSet <ByteCode>(methodDef.Body.ExceptionHandlers.Select(eh => instrToByteCode[eh.HandlerStart])); // Add known states if (methodDef.Body.HasExceptionHandlers) { foreach (ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { ByteCode handlerStart = instrToByteCode[ex.HandlerStart]; handlerStart.StackBefore = new List <StackSlot>(); handlerStart.VariablesBefore = VariableSlot.MakeFullState(varCount); if (ex.HandlerType == ExceptionHandlerType.Catch || ex.HandlerType == ExceptionHandlerType.Filter) { // Catch and Filter handlers start with the exeption on the stack ByteCode ldexception = new ByteCode() { Code = ILCode.Ldexception, Operand = ex.CatchType, PopCount = 0, PushCount = 1 }; ldexceptions[ex] = ldexception; handlerStart.StackBefore.Add(new StackSlot(ldexception)); } agenda.Push(handlerStart); if (ex.HandlerType == ExceptionHandlerType.Filter) { ByteCode filterStart = instrToByteCode[ex.FilterStart]; filterStart.StackBefore = new List <StackSlot>(); filterStart.VariablesBefore = VariableSlot.MakeFullState(varCount); ByteCode ldexception = new ByteCode() { Code = ILCode.Ldexception, Operand = ex.CatchType, PopCount = 0, PushCount = 1 }; // TODO: ldexceptions[ex] = ldexception; filterStart.StackBefore.Add(new StackSlot(ldexception)); agenda.Push(filterStart); } } } body[0].StackBefore = new List <StackSlot>(); body[0].VariablesBefore = VariableSlot.MakeEmptyState(varCount); agenda.Push(body[0]); // Process agenda while (agenda.Count > 0) { ByteCode byteCode = agenda.Pop(); // Calculate new stack List <StackSlot> newStack = StackSlot.CloneStack(byteCode.StackBefore, byteCode.PopCount); for (int i = 0; i < byteCode.PushCount; i++) { newStack.Add(new StackSlot(byteCode)); } // Calculate new variable state VariableSlot[] newVariableState = VariableSlot.CloneVariableState(byteCode.VariablesBefore); if (byteCode.Code == ILCode.Stloc) { int varIndex = ((VariableReference)byteCode.Operand).Index; newVariableState[varIndex] = new VariableSlot(byteCode); } // After the leave, finally block might have touched the variables if (byteCode.Code == ILCode.Leave) { newVariableState = VariableSlot.MakeFullState(varCount); } // Find all successors List <ByteCode> branchTargets = new List <ByteCode>(); if (!byteCode.Code.IsUnconditionalControlFlow()) { if (exceptionHandlerStarts.Contains(byteCode.Next)) { // Do not fall though down to exception handler // It is invalid IL as per ECMA-335 §12.4.2.8.1, but some obfuscators produce it } else { branchTargets.Add(byteCode.Next); } } if (byteCode.Operand is Instruction[]) { foreach (Instruction inst in (Instruction[])byteCode.Operand) { ByteCode target = instrToByteCode[inst]; branchTargets.Add(target); // The target of a branch must have label if (target.Label == null) { target.Label = new ILLabel() { Name = target.Name }; } } } else if (byteCode.Operand is Instruction) { ByteCode target = instrToByteCode[(Instruction)byteCode.Operand]; branchTargets.Add(target); // The target of a branch must have label if (target.Label == null) { target.Label = new ILLabel() { Name = target.Name }; } } // Apply the state to successors foreach (ByteCode branchTarget in branchTargets) { if (branchTarget.StackBefore == null && branchTarget.VariablesBefore == null) { if (branchTargets.Count == 1) { branchTarget.StackBefore = newStack; branchTarget.VariablesBefore = newVariableState; } else { // Do not share data for several bytecodes branchTarget.StackBefore = StackSlot.CloneStack(newStack, 0); branchTarget.VariablesBefore = VariableSlot.CloneVariableState(newVariableState); } agenda.Push(branchTarget); } else { if (branchTarget.StackBefore.Count != newStack.Count) { throw new Exception("Inconsistent stack size at " + byteCode.Name); } // Be careful not to change our new data - it might be reused for several branch targets. // In general, be careful that two bytecodes never share data structures. bool modified = false; // Merge stacks - modify the target for (int i = 0; i < newStack.Count; i++) { ByteCode[] oldPushedBy = branchTarget.StackBefore[i].PushedBy; ByteCode[] newPushedBy = oldPushedBy.Union(newStack[i].PushedBy); if (newPushedBy.Length > oldPushedBy.Length) { branchTarget.StackBefore[i] = new StackSlot(newPushedBy, null); modified = true; } } // Merge variables - modify the target for (int i = 0; i < newVariableState.Length; i++) { VariableSlot oldSlot = branchTarget.VariablesBefore[i]; VariableSlot newSlot = newVariableState[i]; // All can not be unioned further if (!oldSlot.StoredByAll) { if (newSlot.StoredByAll) { branchTarget.VariablesBefore[i] = newSlot; modified = true; } else { ByteCode[] oldStoredBy = oldSlot.StoredBy; ByteCode[] newStoredBy = oldStoredBy.Union(newSlot.StoredBy); if (newStoredBy.Length > oldStoredBy.Length) { branchTarget.VariablesBefore[i] = new VariableSlot(newStoredBy, false); modified = true; } } } } if (modified) { agenda.Push(branchTarget); } } } } // Occasionally the compilers or obfuscators generate unreachable code (which migt be intentonally invalid) // I belive it is safe to just remove it body.RemoveAll(b => b.StackBefore == null); // Genertate temporary variables to replace stack foreach (ByteCode byteCode in body) { int argIdx = 0; int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count; for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) { ILVariable tmpVar = new ILVariable() { Name = string.Format("arg_{0:X2}_{1}", byteCode.Offset, argIdx), IsGenerated = true }; byteCode.StackBefore[i] = new StackSlot(byteCode.StackBefore[i].PushedBy, tmpVar); foreach (ByteCode pushedBy in byteCode.StackBefore[i].PushedBy) { if (pushedBy.StoreTo == null) { pushedBy.StoreTo = new List <ILVariable>(1); } pushedBy.StoreTo.Add(tmpVar); } argIdx++; } } // Try to use single temporary variable insted of several if possilbe (especially useful for dup) // This has to be done after all temporary variables are assigned so we know about all loads foreach (ByteCode byteCode in body) { if (byteCode.StoreTo != null && byteCode.StoreTo.Count > 1) { var locVars = byteCode.StoreTo; // For each of the variables, find the location where it is loaded - there should be preciesly one var loadedBy = locVars.Select(locVar => body.SelectMany(bc => bc.StackBefore).Single(s => s.LoadFrom == locVar)).ToList(); // We now know that all the variables have a single load, // Let's make sure that they have also a single store - us if (loadedBy.All(slot => slot.PushedBy.Length == 1 && slot.PushedBy[0] == byteCode)) { // Great - we can reduce everything into single variable ILVariable tmpVar = new ILVariable() { Name = string.Format("expr_{0:X2}", byteCode.Offset), IsGenerated = true }; byteCode.StoreTo = new List <ILVariable>() { tmpVar }; foreach (ByteCode bc in body) { for (int i = 0; i < bc.StackBefore.Count; i++) { // Is it one of the variable to be merged? if (locVars.Contains(bc.StackBefore[i].LoadFrom)) { // Replace with the new temp variable bc.StackBefore[i] = new StackSlot(bc.StackBefore[i].PushedBy, tmpVar); } } } } } } // Split and convert the normal local variables ConvertLocalVariables(body); // Convert branch targets to labels foreach (ByteCode byteCode in body) { if (byteCode.Operand is Instruction[]) { List <ILLabel> newOperand = new List <ILLabel>(); foreach (Instruction target in (Instruction[])byteCode.Operand) { newOperand.Add(instrToByteCode[target].Label); } byteCode.Operand = newOperand.ToArray(); } else if (byteCode.Operand is Instruction) { byteCode.Operand = instrToByteCode[(Instruction)byteCode.Operand].Label; } } // Convert parameters to ILVariables ConvertParameters(body); return(body); }
/// <summary> /// Update the state of the given branch targets (of the given bytecode). /// Add modified branch targets to the given agenda. /// </summary> private static void UpdateBranchTarget(ByteCode byteCode, ByteCode branchTarget, bool canShareNewState, StackSlot[] newStack, VariableSlot[] newVariableState, Stack<ByteCode> agenda) { if ((branchTarget.StackBefore == null) && (branchTarget.VariablesBefore == null)) { // Branch target has not been processed at all if (canShareNewState) { branchTarget.StackBefore = newStack; branchTarget.VariablesBefore = newVariableState; } else { // Do not share data for several bytecodes branchTarget.StackBefore = StackSlot.ModifyStack(newStack, 0, 0, null); branchTarget.VariablesBefore = VariableSlot.CloneVariableState(newVariableState); } agenda.Push(branchTarget); return; } // If we get here, the branch target has been processed before. // See the the stack size is the same and merge the state where needed. if ((branchTarget.StackBefore == null) || (branchTarget.StackBefore.Length != newStack.Length)) { throw new Exception("Inconsistent stack size at " + byteCode.Name); } // Be careful not to change our new data - it might be reused for several branch targets. // In general, be careful that two bytecodes never share data structures. var modified = false; // Merge stacks - modify the target for (var i = 0; i < newStack.Length; i++) { var oldDefs = branchTarget.StackBefore[i].Definitions; var newDefs = oldDefs.Union(newStack[i].Definitions); if (newDefs.Length > oldDefs.Length) { branchTarget.StackBefore[i] = new StackSlot(newDefs, null); modified = true; } } // Merge variables - modify the target for (var i = 0; i < newVariableState.Length; i++) { var oldSlot = branchTarget.VariablesBefore[i]; var newSlot = newVariableState[i]; if (oldSlot.UnknownDefinition) continue; if (newSlot.UnknownDefinition) { branchTarget.VariablesBefore[i] = newSlot; modified = true; } else { var oldDefs = oldSlot.Definitions; var newDefs = oldDefs.Union(newSlot.Definitions); if (newDefs.Length > oldDefs.Length) { branchTarget.VariablesBefore[i] = new VariableSlot(newDefs, false); modified = true; } } } if (modified) { agenda.Push(branchTarget); } }
public static void _doPropAssigning(ClassPropertyGetter prop,StackFrame frame, OpStep step,Player player,RunTimeScope scope, ASBinCode.rtData.rtObjectBase bindobj,RunTimeValueBase v,StackSlot sslot) { do { if (prop.setter == null) { frame.throwError( step.token,0,"Illegal write to read-only property " ); break; } //检查访问权限 CodeBlock block = player.swc.blocks[scope.blockId]; Class finder; if (block.isoutclass) { var c = prop._class; if (c.instanceClass != null) { c = c.instanceClass; } if (c.mainClass != null) { c = c.mainClass; } if (block.define_class_id == c.classid) { finder = player.swc.classes[block.define_class_id]; } else { finder = null; } } else { finder = player.swc.classes[block.define_class_id]; } var setter = ClassMemberFinder.find(prop._class,prop.setter.name,finder); if (setter == null || setter.bindField != prop.setter) { frame.throwError( step.token,0,"Illegal write to read-only property " ); break; } //***读取setter*** RunTimeValueBase func; if (sslot.stackObjects.superPropBindClass != null) { func = ((MethodGetterBase)setter.bindField).getSuperMethod( bindobj.objScope, sslot.stackObjects.superPropBindClass ); } else { func = ((MethodGetterBase)setter.bindField).getMethod( bindobj ); } //***调用设置器*** var funCaller = frame.player.funcCallerPool.create(frame,step.token); funCaller.SetFunction((ASBinCode.rtData.rtFunction)func); ((ASBinCode.rtData.rtFunction)func).Clear(); funCaller.loadDefineFromFunction(); if (!funCaller.createParaScope()) { return; } //funCaller.releaseAfterCall = true; bool success; funCaller.pushParameter(v,0,out success); if (!success) { frame.endStep(step); return; } funCaller._tempSlot = frame._tempSlot1; funCaller.returnSlot = frame._tempSlot1; BlockCallBackBase cb = frame.player.blockCallBackPool.create(); cb.setCallBacker(_assign_callbacker); cb.step = step; cb.args = frame; funCaller.callbacker = cb; funCaller.call(); return; } while (false); frame.endStep(step); }
public static void execAssigning(StackFrame frame, ASBinCode.OpStep step, ASBinCode.RunTimeScope scope) { ASBinCode.SLOT slot = step.reg.getSlotForAssign(scope,frame); ASBinCode.RunTimeValueBase v = step.arg1.getValue(scope,frame); bool success; var lt = slot.assign(v,out success); if (!success) //(!slot.directSet(v)) { if (!(slot is StackSlot)) //直接赋值时 { //ext = "Illegal assignment to function " + ((MethodGetterBase)step.reg).name + "."; } else { StackSlot oslot = (StackSlot)slot; //if (oslot.linktarget != null) { //slot = oslot.linktarget; slot = lt; } if (step.arg1 is IMemReg) { //将其暂存到临时槽内 frame._tempSlot2.directSet(v); v = frame._tempSlot2.getValue(); } if (slot is SetThisItemSlot) { _doSetThisItem(((SetThisItemSlot)slot).bindObj,v,((SetThisItemSlot)slot).setindex,oslot,frame,step); return; } if (slot is ClassPropertyGetter.PropertySlot) { ClassPropertyGetter.PropertySlot propslot = (ASBinCode.ClassPropertyGetter.PropertySlot)slot; //***调用访问器。*** ASBinCode.ClassPropertyGetter prop = oslot.stackObjects.propGetSet; //propslot.property; _doPropAssigning(prop,frame,step,frame.player,scope, //propslot.bindObj oslot.stackObjects.propBindObj ,v, oslot ); return; } if (slot is OpVector.vectorSLot) //Vector类型不匹配 { BlockCallBackBase cb = frame.player.blockCallBackPool.create(); cb.scope = scope; cb.step = step; cb.args = frame; cb.setCallBacker(_vectorConvertCallBacker); cb.cacheObjects[0] = slot; //***调用强制类型转换*** OpCast.CastValue(v,((OpVector.vectorSLot)slot).vector_data.vector_type, frame,step.token,scope,frame._tempSlot1,cb,false); return; } if (slot is ObjectMemberSlot && !((ObjectMemberSlot)slot).isConstMember) { BlockCallBackBase cb = frame.player.blockCallBackPool.create(); cb.scope = scope; cb.step = step; cb.args = frame; cb.setCallBacker(_objectmemberslotConvertCallbacker); cb.cacheObjects[0] = slot; //***调用强制类型转换*** OpCast.CastValue(v,((ObjectMemberSlot)slot).slottype, frame,step.token,scope,frame._tempSlot1,cb,false); return; } } string ext = String.Empty; if (slot is MethodGetterBase.MethodSlot) { ext = "Cannot assign to a method "; // + ((ASBinCode.ClassMethodGetter.MethodSlot)slot).method; } else if (slot is ObjectMemberSlot) { ext = "Illegal write to read-only property "; //+ ((ObjectMemberSlot)slot).obj.value._class.name //+" on ppp.PPC." } else if (slot is ClassPropertyGetter.PropertySlot) { ext = "Illegal write to read-only property "; } else if (slot is OpAccess_Dot.prototypeSlot) { ext = "Cannot create property " + ((OpAccess_Dot.prototypeSlot)slot)._protoname + " on " + ((OpAccess_Dot.prototypeSlot)slot)._protoRootObj.value._class.name; } frame.throwError( step.token,0,ext ); frame.endStep(step); } else { frame.endStepNoError(); } }
public static void exec_try_read_prop(StackFrame frame, OpStep step, RunTimeScope scope) { ASBinCode.SLOT slot = ((StackSlotAccessor)step.arg1).getSlot(scope,frame); if (slot.isPropGetterSetter) { ((StackSlot)slot).linkTo(null); _do_prop_read( ((StackSlot)slot).stackObjects.propGetSet, frame,step,frame.player,scope,((StackSlot)slot).stackObjects.propBindObj,((StackSlot)slot).stackObjects.superPropBindClass ); } else if (slot.isSetThisItem) { SetThisItemSlot sslot = (SetThisItemSlot)((StackSlot)slot).getLinkSlot(); ((StackSlot)slot).linkTo(null); //***调用索引器get*** RunTimeValueBase func; var rtObj = sslot.bindObj; var player = frame.player; var v2 = sslot.setindex; func = ((MethodGetterBase)sslot.get_this_item.bindField).getMethod( rtObj ); var funCaller = player.funcCallerPool.create(frame,step.token); funCaller.SetFunction((ASBinCode.rtData.rtFunction)func); ((ASBinCode.rtData.rtFunction)func).Clear(); funCaller.loadDefineFromFunction(); if (!funCaller.createParaScope()) { return; } //funCaller.releaseAfterCall = true; bool success; funCaller.pushParameter(v2,0,out success); if (!success) { frame.endStep(step); return; } funCaller._tempSlot = frame._tempSlot1; funCaller.returnSlot = step.reg.getSlot(scope,frame); StackSlot ret = (StackSlot)funCaller.returnSlot; ret.stackObjects._temp_try_write_setthisitem = ret._cache_setthisslot; ret.refPropChanged = true; ret._cache_setthisslot.bindObj = rtObj; ret._cache_setthisslot.setindex = v2; ret._cache_setthisslot.set_this_item = sslot.set_this_item; BlockCallBackBase cb = frame.player.blockCallBackPool.create(); cb.setCallBacker(D_get_this_item_callbacker); cb.step = step; cb.args = frame; funCaller.callbacker = cb; funCaller.call(); return; } else { SLOT regslot = step.reg.getSlot(scope,frame); StackSlot d = regslot as StackSlot; StackSlot s = slot as StackSlot; if (d != null && s != null && s.getLinkSlot() != null) { d.linkTo(s.getLinkSlot()); s.linkTo(null); } else { regslot.directSet(slot.getValue()); } //frame.endStep(step); frame.endStepNoError(); } }
public static StackSlot[] ModifyStackDup2X2(StackSlot[] stack) { var s1 = stack[stack.Length - 1]; var s2 = stack[stack.Length - 2]; if (s1.IsCategory2 && s2.IsCategory2) { // Form 4 return ModifyStackDupX1(stack); } var s3 = stack[stack.Length - 3]; if (s3.IsCategory2 && !s1.IsCategory2 && !s2.IsCategory2) { // Form 3 var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var value3 = stack[stack.Length - 3].Definitions; var newStack = new StackSlot[stack.Length - 3 + 5]; Array.Copy(stack, newStack, stack.Length - 3); newStack[newStack.Length - 5] = new StackSlot(value2, null); newStack[newStack.Length - 4] = new StackSlot(value1, null); newStack[newStack.Length - 3] = new StackSlot(value3, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return newStack; } if (s1.IsCategory2) { // Form 2 var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var value3 = stack[stack.Length - 3].Definitions; var newStack = new StackSlot[stack.Length - 3 + 4]; Array.Copy(stack, newStack, stack.Length - 3); newStack[newStack.Length - 4] = new StackSlot(value1, null); newStack[newStack.Length - 3] = new StackSlot(value3, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return newStack; } else { var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var value3 = stack[stack.Length - 3].Definitions; var value4 = stack[stack.Length - 4].Definitions; var newStack = new StackSlot[stack.Length - 4 + 6]; Array.Copy(stack, newStack, stack.Length - 4); newStack[newStack.Length - 6] = new StackSlot(value2, null); newStack[newStack.Length - 5] = new StackSlot(value1, null); newStack[newStack.Length - 4] = new StackSlot(value4, null); newStack[newStack.Length - 3] = new StackSlot(value3, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return newStack; } }
public static StackSlot[] ModifyStackPop2(StackSlot[] stack) { if (stack[stack.Length - 1].IsCategory2) { // Form 2 return ModifyStack(stack, 1, 0, null); } else { // Form 1 return ModifyStack(stack, 2, 0, null); } }
public static void exec_AccessorBind_ConvertIdx(StackFrame frame, OpStep step, RunTimeScope scope) { RunTimeValueBase obj = step.arg1.getValue(scope, frame); if (rtNull.nullptr.Equals(obj)) { frame.throwError( step.token, 1009, "Cannot access a property or method of a null object reference." ); frame.endStep(); return; } ASBinCode.rtti.Vector_Data vector = (ASBinCode.rtti.Vector_Data)((ASBinCode.rtti.HostedObject)((ASBinCode.rtData.rtObjectBase)obj).value).hosted_object; var idxvalue = step.arg2.getValue(scope, frame); double idx = double.NaN; if (idxvalue.rtType > RunTimeDataType.unknown) { RunTimeDataType ot; if (TypeConverter.Object_CanImplicit_ToPrimitive(idxvalue.rtType, frame.player.swc, out ot)) { var v = TypeConverter.ObjectImplicit_ToPrimitive((rtObjectBase)idxvalue); idx = TypeConverter.ConvertToNumber(v); } } else if (idxvalue.rtType == RunTimeDataType.rt_string || idxvalue.rtType == RunTimeDataType.rt_int || idxvalue.rtType == RunTimeDataType.rt_number || idxvalue.rtType == RunTimeDataType.rt_uint ) { idx = TypeConverter.ConvertToNumber(idxvalue); } if (double.IsNaN(idx)) { frame.throwError( step.token, 0, "索引" + idxvalue + "不能转为int" ); } else { int index = (int)idx; if (index < 0 || index > vector.innnerList.Count) { frame.throwError(step.token, 1125, "The index " + index + " is out of range " + vector.innnerList.Count + "."); } StackSlotAccessor reg = (StackSlotAccessor)step.reg; if (idx == vector.innnerList.Count) { if (vector.isFixed || !reg._isassigntarget) { frame.throwError(step.token, 1125, "The index " + idx + " is out of range " + vector.innnerList.Count + "."); frame.endStep(step); return; } else { vector.innnerList.Add(TypeConverter.getDefaultValue(vector.vector_type).getValue(null, null)); } } StackSlot slot = (StackSlot)step.reg.getSlot(scope, frame); if (reg._isassigntarget || reg._hasUnaryOrShuffixOrDelete) { slot._cache_vectorSlot.idx = index; slot._cache_vectorSlot.vector_data = vector; slot.linkTo(slot._cache_vectorSlot); } else { slot.directSet(vector.innnerList[index]); } } frame.endStep(step); }
public static void exec_AccessorBind(StackFrame frame, OpStep step, RunTimeScope scope) { RunTimeValueBase obj = step.arg1.getValue(scope, frame); if (rtNull.nullptr.Equals(obj)) { frame.throwError( step.token, 1009, "Cannot access a property or method of a null object reference." ); frame.endStep(); return; } ASBinCode.rtti.Vector_Data vector = (ASBinCode.rtti.Vector_Data)((ASBinCode.rtti.HostedObject)((rtObjectBase)obj).value).hosted_object; int idx = TypeConverter.ConvertToInt(step.arg2.getValue(scope, frame)); if (idx < 0 || idx > vector.innnerList.Count) { frame.throwError(step.token, 1125, "The index " + idx + " is out of range " + vector.innnerList.Count + "."); } StackSlotAccessor reg = (StackSlotAccessor)step.reg; if (idx == vector.innnerList.Count) { if (vector.isFixed || !reg._isassigntarget) { frame.throwError(step.token, 1125, "The index " + idx + " is out of range " + vector.innnerList.Count + "." ); frame.endStep(step); return; } else { vector.innnerList.Add(TypeConverter.getDefaultValue(vector.vector_type).getValue(null, null)); } } StackSlot slot = (StackSlot)step.reg.getSlot(scope, frame); if (reg._isassigntarget || reg._hasUnaryOrShuffixOrDelete) { slot._cache_vectorSlot.idx = idx; slot._cache_vectorSlot.vector_data = vector; slot.linkTo(slot._cache_vectorSlot); } else { slot.directSet(vector.innnerList[idx]); } frame.endStep(step); }
List <ILNode> ConvertToAst(List <ByteCode> body) { List <ILNode> ast = new List <ILNode>(); // Convert stack-based IL code to ILAst tree foreach (ByteCode byteCode in body) { ILRange ilRange = new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset }; if (byteCode.StackBefore == null) { // Unreachable code continue; } ILExpression expr = new ILExpression(byteCode.Code, byteCode.Operand); expr.ILRanges.Add(ilRange); if (byteCode.Prefixes != null && byteCode.Prefixes.Length > 0) { ILExpressionPrefix[] prefixes = new ILExpressionPrefix[byteCode.Prefixes.Length]; for (int i = 0; i < prefixes.Length; i++) { prefixes[i] = new ILExpressionPrefix((ILCode)byteCode.Prefixes[i].OpCode.Code, byteCode.Prefixes[i].Operand); } expr.Prefixes = prefixes; } // Label for this instruction if (byteCode.Label != null) { ast.Add(byteCode.Label); } // Reference arguments using temporary variables int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count; for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) { StackSlot slot = byteCode.StackBefore[i]; expr.Arguments.Add(new ILExpression(ILCode.Ldloc, slot.LoadFrom)); } // Store the result to temporary variable(s) if needed if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) { ast.Add(expr); } else if (byteCode.StoreTo.Count == 1) { ast.Add(new ILExpression(ILCode.Stloc, byteCode.StoreTo[0], expr)); } else { ILVariable tmpVar = new ILVariable() { Name = "expr_" + byteCode.Offset.ToString("X2"), IsGenerated = true }; ast.Add(new ILExpression(ILCode.Stloc, tmpVar, expr)); foreach (ILVariable storeTo in byteCode.StoreTo.AsEnumerable().Reverse()) { ast.Add(new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, tmpVar))); } } } return(ast); }
public static StackSlot[] ModifyStackDup2X1(StackSlot[] stack) { if (stack[stack.Length - 1].IsCategory2) { // Form 2 return ModifyStackDupX1(stack); } else { // Form 1 var value1 = stack[stack.Length - 1].Definitions; var value2 = stack[stack.Length - 2].Definitions; var value3 = stack[stack.Length - 3].Definitions; var newStack = new StackSlot[stack.Length - 3 + 5]; Array.Copy(stack, newStack, stack.Length - 3); newStack[newStack.Length - 5] = new StackSlot(value2, null); newStack[newStack.Length - 4] = new StackSlot(value1, null); newStack[newStack.Length - 3] = new StackSlot(value3, null); newStack[newStack.Length - 2] = new StackSlot(value2, null); newStack[newStack.Length - 1] = new StackSlot(value1, null); return newStack; } }