public JavaBytecodeWriter AddInstruction(JavaInstruction i) { outputCode.Add(i); if (OnNextInstruction != null) { OnNextInstruction(i); OnNextInstruction = null; } return(this); }
private void CompileSwitch(ILSwitch node) { CompileExpression(node.Condition, ExpectType.Primitive); //TODO: Switch on long JavaBytecodeWriter.LookupswitchOperand operand = new JavaBytecodeWriter.LookupswitchOperand(); JavaInstruction switchInstr = new JavaInstruction(Java.OpCodes.lookupswitch, null, node); codeGenerator.AddInstruction(switchInstr); string labelsSufix = rnd.Next().ToString(); string defaultLabel = "default" + labelsSufix; string exitLabel = "exit" + labelsSufix; bool wasDefault = false; List <Tuple <int, string> > pairs = new List <Tuple <int, string> >(); loopOrSwitchExitLabel.Push(exitLabel); int index = 0; foreach (ILSwitch.CaseBlock caseBlock in node.CaseBlocks) { if (caseBlock.Values == null) { codeGenerator.Label(defaultLabel); wasDefault = true; } else { string thisCaseLabel = "case" + (index++) + labelsSufix; foreach (int val in caseBlock.Values) { pairs.Add(new Tuple <int, string>(val, thisCaseLabel)); } codeGenerator.Label(thisCaseLabel); } CompileBlock(caseBlock); } loopOrSwitchExitLabel.Pop(); if (!wasDefault) { codeGenerator.Label(defaultLabel); } codeGenerator.Label(exitLabel); pairs.Sort((T1, T2) => (T1.Item1 <T2.Item1 ? -1 : T1.Item1> T2.Item1 ? 1 : 0)); operand.DefaultLabel = defaultLabel; operand.Pairs = pairs.ToArray(); switchInstr.Operand = operand; }
private byte[] LinkPass2() { MemoryStream codeBytesStream = new MemoryStream(); BinaryWriter codeBytesWriter = new BinaryWriter(codeBytesStream); for (int i = 0; i < outputCode.Count; i++) { JavaInstruction instr = outputCode[i]; codeBytesWriter.Write((byte)instr.Opcode); Java.ByteCode.JavaInstructionDescption descr = Java.ByteCode.JavaInstructions[instr.Opcode]; int operandSize = descr.Size - 1; switch (descr.OpType) { case Java.ByteCode.JavaOperandType.ConstValue: switch (operandSize) { case 1: codeBytesWriter.Write((sbyte)instr.Operand); break; case 2: codeBytesWriter.WriteBE((short)instr.Operand); break; case 4: codeBytesWriter.WriteBE((int)instr.Operand); break; } break; case Java.ByteCode.JavaOperandType.ConstPool: if (operandSize == 1) { codeBytesWriter.Write((byte)((ushort)instr.Operand)); } else { codeBytesWriter.WriteBE((ushort)instr.Operand); } break; case Java.ByteCode.JavaOperandType.LocalVar: if (instr.Operand is ushort) { codeBytesWriter.WriteBE((ushort)instr.Operand); } else { codeBytesWriter.Write((byte)instr.Operand); } break; case Java.ByteCode.JavaOperandType.Offset: if (instr.Operand is string) { codeBytesWriter.WriteBE((short)(outputCodeOffsets[outputCode[labels[(string)instr.Operand]]] - outputCodeOffsets[instr])); } else { codeBytesWriter.WriteBE((short)(outputCodeOffsets[(JavaInstruction)instr.Operand] - outputCodeOffsets[instr])); } break; case Java.ByteCode.JavaOperandType.Special: switch (instr.Opcode) { case Java.OpCodes.iinc: if (instr.Operand is int) { codeBytesWriter.WriteBE((int)instr.Operand); } else { codeBytesWriter.WriteBE((short)instr.Operand); } break; case Java.OpCodes.tableswitch: //TODO: Java.OpCodes.tableswitch break; case Java.OpCodes.lookupswitch: LookupswitchOperand lookUpOperand = (LookupswitchOperand)instr.Operand; int padding = (4 - ((outputCodeOffsets[instr] + 1) % 4)) % 4; codeBytesWriter.Write(new byte[padding]); codeBytesWriter.WriteBE(outputCodeOffsets[outputCode[labels[lookUpOperand.DefaultLabel]]] - outputCodeOffsets[instr]); codeBytesWriter.WriteBE(lookUpOperand.Pairs.Length); for (int j = 0; j < lookUpOperand.Pairs.Length; j++) { codeBytesWriter.WriteBE(lookUpOperand.Pairs[j].Item1); codeBytesWriter.WriteBE(outputCodeOffsets[outputCode[labels[lookUpOperand.Pairs[j].Item2]]] - outputCodeOffsets[instr]); } break; case Java.OpCodes.invokeinterface: case Java.OpCodes.invokedynamic: uint op = (uint)instr.Operand; codeBytesWriter.WriteBE((ushort)(op & 0xfff)); codeBytesWriter.WriteBE((ushort)(op >> 16)); break; case Java.OpCodes.newarray: codeBytesWriter.Write((byte)instr.Operand); break; case Java.OpCodes.wide: break; case Java.OpCodes.multianewarray: int data = (int)instr.Operand; codeBytesWriter.WriteBE((ushort)(data & 0xffff)); codeBytesWriter.Write((byte)((data & 0xff0000) >> 16)); break; } break; } } byte[] result = codeBytesStream.ToArray(); codeBytesStream.Close(); return(result); }
private void LinkPass1(Java.ConstantPool pool) { int offset = StartOffset; bool lastWide = false; for (int i = 0; i < outputCode.Count; i++) { JavaInstruction instr = outputCode[i]; outputCodeOffsets.Add(instr, offset); object lastOperand = instr.Operand; if (instr.Operand is Java.Constant) { instr.Operand = pool.AddConstant((Java.Constant)instr.Operand); } else if (instr.Operand is MultianewarrayOperand) { MultianewarrayOperand operand = (MultianewarrayOperand)instr.Operand; instr.Operand = pool.AddConstant(operand.ClassOperand) | (operand.DimensionsOperand << 16); } if (instr.Opcode == Java.OpCodes.ldc) { if (((ushort)instr.Operand) > byte.MaxValue) { instr.Opcode = Java.OpCodes.ldc_w; } } if (instr.Opcode == Java.OpCodes.invokeinterface) { if (lastOperand is Java.Constants.MethodRef) { Java.Constants.MethodRef m = (Java.Constants.MethodRef)lastOperand; lastOperand = new Java.Constants.InterfaceMethodRef(m.Class, m.Name, m.Descriptor); } byte argsCount = CalculateInterfaceCallArgsCount(((Java.Constants.InterfaceMethodRef)lastOperand).Descriptor); ushort constIndex = (ushort)instr.Operand; instr.Operand = (uint)(constIndex | ((argsCount + 1) << 24)); } int size = Java.ByteCode.JavaInstructions[instr.Opcode].Size; if ((size == -1) && (instr.Opcode == Java.OpCodes.lookupswitch)) { LookupswitchOperand op = (LookupswitchOperand)lastOperand; instr.Operand = op; int paddingLendth = (4 - ((offset + 1) % 4)) % 4; size = 1 //opcode + paddingLendth //padding + 4 //default + 4 //npairs + op.Pairs.Length * 8; //pairs count * pairs size (8 = 4 + 4) } if (lastWide) { size = (size - 1) * 2 + 1; lastWide = false; } offset += size; if (instr.Opcode == Java.OpCodes.wide) { lastWide = true; } } }