private object[] ExtractParameters(MethodRefConstantPoolItem methodRef) { int parametersCount = methodRef.Signature.ParametersCount; object[] parameters = new object[parametersCount]; for (int i = parametersCount - 1; i >= 0; i--) { parameters[i] = operandStack.Pop(); } return(parameters); }
public void PrepareStaticMethodInvocation(object[] parameters, MethodRefConstantPoolItem methodRef) { JavaClass javaClass = classArea.GetClass(methodRef.Class.Name); classArea.InitializeClass(javaClass); MethodInfo methodToRun = javaClass.GetMethodInfo(methodRef); if (!methodToRun.AccessFlags.HasFlag(MethodAccessFlags.Static)) { throw new InvalidOperationException(string.Format("Method {0} on class {1} was caled using invokestatic, but it is not static method!", methodToRun.Name, methodToRun.Class.Name)); } if (methodToRun.IsInitializationMethod) { throw new InvalidOperationException(string.Format("Method {0} on class {1} was caled using invokestatic, but it is an initialization method!", methodToRun.Name, methodToRun.Class.Name)); } PrepareMethodInvocation(methodToRun, null, parameters); }
public void Run() { byte[] code = codeInfo.Code; int codeLength = code.Length; //helper variables int index = 0; int newPC = 0; object[] array = null; object value = null; int iValue = 0; long lValue = 0; float fValue = 0; double dValue = 0; byte atype = 0; JavaInstance instance = null; MethodRefConstantPoolItem methodRef = null; var instruction = (Instruction)code.ReadByte(ref pc); switch (instruction) { case Instruction.nop: return; case Instruction.aconst_null: operandStack.Push(null); return; case Instruction.iconst_m1: operandStack.Push((int)-1); return; case Instruction.iconst_0: operandStack.Push((int)0); return; case Instruction.iconst_1: operandStack.Push((int)1); return; case Instruction.iconst_2: operandStack.Push((int)2); return; case Instruction.iconst_3: operandStack.Push((int)3); return; case Instruction.iconst_4: operandStack.Push((int)4); return; case Instruction.iconst_5: operandStack.Push((int)5); return; case Instruction.lconst_0: operandStack.Push((long)0); return; case Instruction.lconst_1: operandStack.Push((long)1); return; case Instruction.fconst_0: operandStack.Push((float)0.0); return; case Instruction.fconst_1: operandStack.Push((float)1.0); return; case Instruction.fconst_2: operandStack.Push((float)2.0); return; case Instruction.dconst_0: operandStack.Push((double)0.0); return; case Instruction.dconst_1: operandStack.Push((double)1.0); return; case Instruction.bipush: operandStack.Push((int)code.ReadSByte(ref pc)); return; case Instruction.sipush: operandStack.Push((int)code.ReadShort(ref pc)); return; //LDC instruction throws if used for class, method type or method handle constant pool items case Instruction.ldc: index = code.ReadByte(ref pc); environment.LoadConstant(index); return; case Instruction.ldc_w: index = code.ReadShort(ref pc); environment.LoadConstant(index); return; case Instruction.ldc2_w: index = code.ReadShort(ref pc); environment.LoadConstant(index); return; case Instruction.iload: case Instruction.lload: case Instruction.fload: case Instruction.dload: case Instruction.aload: index = ReadWithWideCheck(code); operandStack.Push(locals[index]); return; case Instruction.iload_0: case Instruction.lload_0: case Instruction.fload_0: case Instruction.dload_0: case Instruction.aload_0: operandStack.Push(locals[0]); return; case Instruction.iload_1: case Instruction.lload_1: case Instruction.fload_1: case Instruction.dload_1: case Instruction.aload_1: operandStack.Push(locals[1]); return; case Instruction.iload_2: case Instruction.lload_2: case Instruction.fload_2: case Instruction.dload_2: case Instruction.aload_2: operandStack.Push(locals[2]); return; case Instruction.iload_3: case Instruction.lload_3: case Instruction.fload_3: case Instruction.dload_3: case Instruction.aload_3: operandStack.Push(locals[3]); return; case Instruction.iaload: case Instruction.laload: case Instruction.faload: case Instruction.daload: case Instruction.aaload: case Instruction.baload: case Instruction.caload: case Instruction.saload: index = operandStack.PopInt(); array = operandStack.PopArray(); if (array == null) { environment.SignalException(NullPointerExceptionClass.Name); return; } if (index < 0 || index >= array.Length) { environment.SignalException(ArrayIndexOutOfBoundsExceptionClass.Name, ClassDefaults.IntVoidMethodDescriptor, new object[1] { index }); return; } operandStack.Push(array[index]); return; case Instruction.istore: case Instruction.lstore: case Instruction.fstore: case Instruction.dstore: case Instruction.astore: index = ReadWithWideCheck(code); locals[index] = operandStack.Pop(); return; case Instruction.istore_0: case Instruction.lstore_0: case Instruction.fstore_0: case Instruction.dstore_0: case Instruction.astore_0: locals[0] = operandStack.Pop(); return; case Instruction.istore_1: case Instruction.lstore_1: case Instruction.fstore_1: case Instruction.dstore_1: case Instruction.astore_1: locals[1] = operandStack.Pop(); return; case Instruction.istore_2: case Instruction.lstore_2: case Instruction.fstore_2: case Instruction.dstore_2: case Instruction.astore_2: locals[2] = operandStack.Pop(); return; case Instruction.istore_3: case Instruction.lstore_3: case Instruction.fstore_3: case Instruction.dstore_3: case Instruction.astore_3: locals[3] = operandStack.Pop(); return; case Instruction.iastore: case Instruction.lastore: case Instruction.fastore: case Instruction.dastore: case Instruction.aastore: //TODO: mel by vyhazovat i ArrayStoreException .... JVM 7 spec page 371 case Instruction.bastore: case Instruction.castore: case Instruction.sastore: value = operandStack.Pop(); index = operandStack.PopInt(); array = operandStack.PopArray(); if (array == null) { environment.SignalException(NullPointerExceptionClass.Name); return; } if (index < 0 || index >= array.Length) { environment.SignalException(ArrayIndexOutOfBoundsExceptionClass.Name, ClassDefaults.IntVoidMethodDescriptor, new object[1] { index }); return; } array[index] = value; return; case Instruction.pop: operandStack.Pop(); return; case Instruction.pop2: // JVM stings..... value = operandStack.Pop(); if (!value.IsCategory2Type()) { operandStack.Pop(); } return; case Instruction.dup: Dup(); return; case Instruction.dup_x1: DupX1(); return; case Instruction.dup_x2: DupX2(); return; case Instruction.dup2: Dup2(); return; case Instruction.dup2_x1: Dup2X1(); return; case Instruction.dup2_x2: Dup2X2(); return; case Instruction.swap: value = operandStack.Pop(); operandStack.PushMany(value, operandStack.Pop()); return; case Instruction.iadd: operandStack.Push(operandStack.PopInt() + operandStack.PopInt()); return; case Instruction.ladd: operandStack.Push(operandStack.PopLong() + operandStack.PopLong()); return; case Instruction.fadd: operandStack.Push(operandStack.PopFloat() + operandStack.PopFloat()); return; case Instruction.dadd: operandStack.Push(operandStack.PopDouble() + operandStack.PopDouble()); return; case Instruction.isub: operandStack.Push(-operandStack.PopInt() + operandStack.PopInt()); return; case Instruction.lsub: operandStack.Push(-operandStack.PopLong() + operandStack.PopLong()); return; case Instruction.fsub: operandStack.Push(-operandStack.PopFloat() + operandStack.PopFloat()); return; case Instruction.dsub: operandStack.Push(-operandStack.PopDouble() + operandStack.PopDouble()); return; case Instruction.imul: operandStack.Push(operandStack.PopInt() * operandStack.PopInt()); return; case Instruction.lmul: operandStack.Push(operandStack.PopLong() * operandStack.PopLong()); return; case Instruction.fmul: operandStack.Push(operandStack.PopFloat() * operandStack.PopFloat()); return; case Instruction.dmul: operandStack.Push(operandStack.PopDouble() * operandStack.PopDouble()); return; case Instruction.idiv: iValue = operandStack.PopInt(); if (iValue == (int)0) { environment.SignalException(ArithmeticExceptionClass.Name, ClassDefaults.StringVoidMethodDescriptor, new object[1] { environment.CreateStringInstance("/ by zero") }); return; } operandStack.Push(operandStack.PopInt() / iValue); return; case Instruction.ldiv: lValue = operandStack.PopLong(); if (lValue == (long)0) { environment.SignalException(ArithmeticExceptionClass.Name, ClassDefaults.StringVoidMethodDescriptor, new object[1] { environment.CreateStringInstance("/ by zero") }); return; } operandStack.Push(operandStack.PopLong() / lValue); return; case Instruction.fdiv: fValue = operandStack.PopFloat(); operandStack.Push(operandStack.PopFloat() / fValue); return; case Instruction.ddiv: dValue = operandStack.PopDouble(); operandStack.Push(operandStack.PopDouble() / dValue); return; case Instruction.irem: iValue = operandStack.PopInt(); if (iValue == (int)0) { environment.SignalException(ArithmeticExceptionClass.Name, ClassDefaults.StringVoidMethodDescriptor, new object[1] { environment.CreateStringInstance("/ by zero") }); return; } operandStack.Push(operandStack.PopInt() % iValue); return; case Instruction.lrem: lValue = operandStack.PopLong(); if (lValue == (long)0) { environment.SignalException(ArithmeticExceptionClass.Name, ClassDefaults.StringVoidMethodDescriptor, new object[1] { environment.CreateStringInstance("/ by zero") }); return; } operandStack.Push(operandStack.PopLong() % lValue); return; case Instruction.frem: fValue = operandStack.PopFloat(); operandStack.Push(operandStack.PopFloat() % fValue); return; case Instruction.drem: dValue = operandStack.PopDouble(); operandStack.Push(operandStack.PopDouble() % dValue); return; case Instruction.ineg: operandStack.Push(-operandStack.PopInt()); return; case Instruction.lneg: operandStack.Push(-operandStack.PopLong()); return; case Instruction.fneg: operandStack.Push(-operandStack.PopFloat()); return; case Instruction.dneg: operandStack.Push(-operandStack.PopDouble()); return; case Instruction.ishl: iValue = operandStack.PopInt(); operandStack.Push(operandStack.PopInt() << iValue); return; case Instruction.lshl: iValue = operandStack.PopInt(); operandStack.Push(operandStack.PopLong() << iValue); return; case Instruction.ishr: iValue = operandStack.PopInt(); operandStack.Push(operandStack.PopInt() >> iValue); return; case Instruction.lshr: iValue = operandStack.PopInt(); operandStack.Push(operandStack.PopLong() >> iValue); return; case Instruction.iushr: iValue = operandStack.PopInt(); operandStack.Push(operandStack.PopUInt() >> iValue); return; case Instruction.lushr: iValue = operandStack.PopInt(); operandStack.Push(operandStack.PopULong() >> iValue); return; case Instruction.iand: operandStack.Push(operandStack.PopInt() & operandStack.PopInt()); return; case Instruction.land: operandStack.Push(operandStack.PopLong() & operandStack.PopLong()); return; case Instruction.ior: operandStack.Push(operandStack.PopInt() | operandStack.PopInt()); return; case Instruction.lor: operandStack.Push(operandStack.PopLong() | operandStack.PopLong()); return; case Instruction.ixor: operandStack.Push(operandStack.PopInt() ^ operandStack.PopInt()); return; case Instruction.lxor: operandStack.Push(operandStack.PopLong() ^ operandStack.PopLong()); return; case Instruction.iinc: index = ReadWithWideCheck(code, unsetWideFlag: false); iValue = wasWideInstruction ? code.ReadShort(ref pc) : code.ReadSByte(ref pc); //not using ReadWithWideCheck, because here must be SIGNED byte read wasWideInstruction = false; locals[index] = (int)locals[index] + iValue; return; case Instruction.i2l: operandStack.Push((long)operandStack.PopInt()); return; case Instruction.i2f: operandStack.Push((float)operandStack.PopInt()); return; case Instruction.i2d: operandStack.Push((double)operandStack.PopInt()); return; case Instruction.l2i: operandStack.Push((int)operandStack.PopLong()); return; case Instruction.l2f: operandStack.Push((float)operandStack.PopLong()); return; case Instruction.l2d: operandStack.Push((double)operandStack.PopLong()); return; case Instruction.f2i: operandStack.Push((int)operandStack.PopFloat()); return; case Instruction.f2l: operandStack.Push((long)operandStack.PopFloat()); return; case Instruction.f2d: operandStack.Push((double)operandStack.PopFloat()); return; case Instruction.d2i: operandStack.Push((int)operandStack.PopDouble()); return; case Instruction.d2l: operandStack.Push((long)operandStack.PopDouble()); return; case Instruction.d2f: operandStack.Push((float)operandStack.PopDouble()); return; case Instruction.i2b: operandStack.Push((int)(byte)operandStack.PopInt()); return; case Instruction.i2c: operandStack.Push((int)(char)operandStack.PopInt()); return; case Instruction.i2s: operandStack.Push((int)(short)operandStack.PopInt()); return; case Instruction.lcmp: LCmp(); return; case Instruction.fcmpl: FCmp(nanIsOne: false); return; case Instruction.fcmpg: FCmp(nanIsOne: true); return; case Instruction.dcmpl: DCmp(nanIsOne: false); return; case Instruction.dcmpg: DCmp(nanIsOne: true); return; case Instruction.ifeq: Jump <int>(v => v == 0, code); return; case Instruction.ifne: Jump <int>(v => v != 0, code); return; case Instruction.iflt: Jump <int>(v => v < 0, code); return; case Instruction.ifge: Jump <int>(v => v >= 0, code); return; case Instruction.ifgt: Jump <int>(v => v > 0, code); return; case Instruction.ifle: Jump <int>(v => v <= 0, code); return; case Instruction.if_icmpeq: JumpTwoValues <int>((v1, v2) => v1 == v2, code); return; case Instruction.if_icmpne: JumpTwoValues <int>((v1, v2) => v1 != v2, code); return; case Instruction.if_icmplt: JumpTwoValues <int>((v1, v2) => v1 < v2, code); return; case Instruction.if_icmpge: JumpTwoValues <int>((v1, v2) => v1 >= v2, code); return; case Instruction.if_icmpgt: JumpTwoValues <int>((v1, v2) => v1 > v2, code); return; case Instruction.if_icmple: JumpTwoValues <int>((v1, v2) => v1 <= v2, code); return; case Instruction.if_acmpeq: JumpTwoValues <JavaInstance>((v1, v2) => v1 == v2, code); return; case Instruction.if_acmpne: JumpTwoValues <JavaInstance>((v1, v2) => v1 != v2, code); return; case Instruction.ifnull: Jump <JavaInstance>(i => i == null, code); return; case Instruction.ifnonnull: Jump <JavaInstance>(i => i != null, code); return; case Instruction.@goto: newPC = pc - 1; pc = newPC + (int)code.ReadShort(ref pc); return; case Instruction.goto_w: newPC = pc - 1; pc = newPC + code.ReadInt(ref pc); return; case Instruction.jsr: newPC = (int)code.ReadShort(ref pc); operandStack.Push(pc); pc = newPC; return; case Instruction.jsr_w: newPC = code.ReadInt(ref pc); operandStack.Push(pc); pc = newPC; return; case Instruction.ret: index = ReadWithWideCheck(code); pc = (int)locals[index]; return; case Instruction.tableswitch: TableSwitch(code); return; case Instruction.lookupswitch: LookupSwitch(code); return; case Instruction.ireturn: case Instruction.lreturn: case Instruction.freturn: case Instruction.dreturn: case Instruction.areturn: environment.PrepareReturn(operandStack.Pop()); return; case Instruction.@return: environment.PrepareReturnVoid(); return; case Instruction.getstatic: environment.GetStaticFieldValue(GetConstantPoolItem <FieldRefConstantPoolItem>(code)); return; case Instruction.putstatic: value = operandStack.Pop(); environment.SetStaticFieldValue(GetConstantPoolItem <FieldRefConstantPoolItem>(code), value); return; case Instruction.getfield: instance = operandStack.PopInstance(); if (instance == null) { environment.SignalException(NullPointerExceptionClass.Name); return; } environment.GetFieldValue(GetConstantPoolItem <FieldRefConstantPoolItem>(code), instance); return; case Instruction.putfield: value = operandStack.Pop(); instance = operandStack.PopInstance(); if (instance == null) { environment.SignalException(NullPointerExceptionClass.Name); return; } environment.SetFieldValue(GetConstantPoolItem <FieldRefConstantPoolItem>(code), instance, value); return; case Instruction.invokestatic: InvokeStatic(code); return; case Instruction.invokevirtual: methodRef = GetConstantPoolItem <MethodRefConstantPoolItem>(code); array = ExtractParameters(methodRef); instance = operandStack.PopInstance(); if (instance == null) { environment.SignalException(NullPointerExceptionClass.Name); return; } environment.PrepareVirtualOrInterfaceMethodInvocation(instance, array, methodRef); return; case Instruction.invokespecial: methodRef = GetConstantPoolItem <MethodRefConstantPoolItem>(code); array = ExtractParameters(methodRef); instance = operandStack.PopInstance(); if (instance == null) { environment.SignalException(NullPointerExceptionClass.Name); return; } environment.PrepareSpecialMethodInvocation(instance, array, methodRef); return; case Instruction.invokeinterface: methodRef = GetConstantPoolItem <MethodRefConstantPoolItem>(code); array = ExtractParameters(methodRef); instance = operandStack.PopInstance(); if (instance == null) { environment.SignalException(NullPointerExceptionClass.Name); return; } environment.PrepareVirtualOrInterfaceMethodInvocation(instance, array, methodRef); pc += 2; //Skip count and 0 parameters return; case Instruction.@new: environment.CreateInstance(GetConstantPoolItem <ClassConstantPoolItem>(code).Name); return; case Instruction.newarray: iValue = operandStack.PopInt(); if (iValue < 0) { environment.SignalException(NegativeArraySizeExceptionClass.Name); return; } atype = code.ReadByte(ref pc); operandStack.Push(CreateArrayWithDefaultValues(atype, iValue)); return; case Instruction.anewarray: pc += 2; //skip classRef iValue = operandStack.PopInt(); if (iValue < 0) { environment.SignalException(NegativeArraySizeExceptionClass.Name); return; } operandStack.Push(new object[iValue]); return; case Instruction.multianewarray: index = code.ReadShort(ref pc); var arrayTypeInfo = Signature.ParseArrayType(ConstantPool.GetItem <ClassConstantPoolItem>(index).Name); int dimensions = code.ReadByte(ref pc); var sizes = new int[dimensions]; for (int i = dimensions - 1; i >= 0; i--) { sizes[i] = operandStack.PopInt(); if (sizes[i] < 0) { environment.SignalException(NegativeArraySizeExceptionClass.Name); return; } } operandStack.Push(CreateMultiArray(arrayTypeInfo, sizes, 0)); return; case Instruction.arraylength: array = operandStack.PopArray(); if (array == null) { environment.SignalException(NullPointerExceptionClass.Name); return; } operandStack.Push(array.Length); return; case Instruction.athrow: instance = operandStack.PopInstance(); if (instance == null) { environment.SignalException(NullPointerExceptionClass.Name); return; } environment.SignalException(instance); return; case Instruction.checkcast: //not implemented but allowed in bytecode (just skiped) pc += 2; return; case Instruction.instanceof: throw new NotImplementedException("Instruction instanceof not implemeted!"); case Instruction.monitorenter: case Instruction.monitorexit: throw new NotImplementedException("monitor instructions not implemnted!"); case Instruction.wide: wasWideInstruction = true; return; case Instruction.breakpoint: case Instruction.impdep1: case Instruction.impdep2: throw new NotImplementedException(string.Format("Reserved instruction {0} is not implemented.", instruction.ToString())); case Instruction.invokedynamic: throw new NotImplementedException("invokedynamic instruction is not supported."); default: throw new InvalidOperationException("Unknown instruction!"); } }
public MethodInfo GetMethodInfo(MethodRefConstantPoolItem methodRef) { return(GetMethodInfo(methodRef.Key)); }
public void PrepareSpecialMethodInvocation(JavaInstance instance, object[] parameters, MethodRefConstantPoolItem methodRef) { MethodInfo methodToRun = classArea.GetClass(methodRef.Class.Name).GetMethodInfo(methodRef); PrepareMethodInvocation(methodToRun, instance, parameters); }
public void PrepareVirtualOrInterfaceMethodInvocation(JavaInstance instance, object[] parameters, MethodRefConstantPoolItem methodRef) { MethodInfo methodToRun = instance.JavaClass.GetMethodInfo(methodRef); if (methodToRun.IsInitializationMethod) { throw new InvalidOperationException(string.Format("Method {0} on class {1} was caled using invokevirtual, but it is an initialization method!", methodToRun.Name, methodToRun.Class.Name)); } PrepareMethodInvocation(methodToRun, instance, parameters); }