public void SetLocalInAllFrames(int index, JavaType type, JavaException.Where Where) { SetLocalInOneFrame(top, index, type, Where); foreach (var kvp in frames) { SetLocalInOneFrame(kvp.Value, index, type, Where); }
public JavaType(string descriptor, JavaException.Where Where) { if (ParseType(descriptor, 0) != descriptor.Length) { throw Where.Exception($"bad field descriptor {descriptor}"); } }
public int Put(JavaConstant newConst, JavaException.Where Where) { var newConstType = newConst.GetType(); int n = pool.Count; for (int i = 1; i < n; i++) { var oldConst = pool[i]; if (oldConst?.GetType() == newConstType && oldConst.Equals(newConst)) { return((ushort)i); } } if (!editable) { throw Where.Exception("new constants not allowed"); } pool.Add(newConst); if (newConst is JavaConstant.Long || newConst is JavaConstant.Double) { pool.Add(null); // section 4.4.5 } return(n); }
public bool LoadFrame(ushort offsetLabel, bool keepStack, JavaException.Where Where) { if (frames.TryGetValue(offsetLabel, out var frame)) { top.locals = new List <JavaType>(frame.locals); if (keepStack) { top.stack = new List <JavaType>(frame.stack); curStack = 0; foreach (var e in top.stack) { curStack += e.Category; } } else { top.stack.Clear(); } return(true); } else if (Where != null) { throw Where.Exception($"missing stack map at offset {offsetLabel:X4}"); } return(false); }
public int GetMaxStackSize(JavaException.Where Where) { if (top.stack.Count != 0) { throw Where.Exception($"operand stack is not empty: [ {string.Join(", ", top.stack)} ]"); } return(maxStack); }
public T Get <T>(int index, JavaException.Where Where) { if (index > 0 && index < pool.Count && pool[index] is T o && o != null) { return(o); } throw Where.Exception($"expected constant of type '{typeof(T).Name}' at index {index}"); }
public JavaType PopStack(JavaException.Where Where) { int n = top.stack.Count - 1; if (n < 0) { throw Where.Exception("underflow in operand stack"); } var retval = top.stack[n]; curStack -= retval.Category; top.stack.RemoveAt(n); return(retval); }
public int[] SaveFrame(ushort offsetLabel, bool branchTarget, JavaException.Where Where) { #if false { Console.WriteLine("-----------> Save Frame at " + offsetLabel.ToString("X4") + " branchTarget " + branchTarget); var(old1, old2) = FrameToString(offsetLabel); var(top1, top2) = FrameToString(); Console.WriteLine("old frame = " + old1 + " ; " + old2); Console.WriteLine("top frame = " + top1 + " ; " + top2); Console.WriteLine(new System.Diagnostics.StackTrace(true).ToString()); Console.WriteLine("<--------------"); } #endif List <JavaType> copyLocals = null; List <JavaType> copyStack = null; int[] resetLocals = null; if (frames.TryGetValue(offsetLabel, out var old)) { if (branchTarget) { // we are saving a frame that is the target of a branch, // so merging should not affect the current stack frame. copyLocals = new List <JavaType>(top.locals); copyStack = new List <JavaType>(top.stack); } resetLocals = MergeFrame(old, offsetLabel, Where); if (branchTarget) { old.branchTarget = true; } } else { top.branchTarget = branchTarget; frames.Add(offsetLabel, top); } var newTop = new Frame(); newTop.locals = copyLocals ?? new List <JavaType>(top.locals); newTop.stack = copyStack ?? new List <JavaType>(top.stack); top = newTop; return(resetLocals); }
public static string Decode(byte[] blk, JavaException.Where Where) { int n = blk.Length; var ch = new char[n]; int i = 0; int j = 0; while (i < n) { byte b0 = blk[i++]; if ((b0 & 0x80) == 0) { // one-byte sequence ch[j++] = (char)b0; continue; } if (i < n) { byte b1 = blk[i++]; if ((b1 & 0xC0) == 0x80) { if ((b0 & 0xE0) == 0xC0) { // two-byte sequence ch[j++] = (char)(((b0 & 0x1F) << 6) + (b1 & 0x3F)); continue; } else if (i < n && (b0 & 0xF0) == 0xE0) { byte b2 = blk[i++]; if ((b1 & 0xC0) == 0x80) { // three-byte sequence ch[j++] = (char) (((b0 & 0x0F) << 12) + ((b1 & 0x3F) << 6) + (b2 & 0x3F)); continue; } } } } throw Where.Exception("invalid UTF-8 data (at offset " + i + " in data)"); } return(new string(ch, 0, j)); }
public JavaMethodType(string descriptor, JavaException.Where Where) { if (descriptor[0] == '(') { var list = new List <JavaFieldRef>(); var index = 1; while (index < descriptor.Length) { if (descriptor[index] == ')') { break; } var nextType = new JavaType(); if ((index = nextType.ParseType(descriptor, index)) == -1) { break; } else { list.Add(new JavaFieldRef(null, nextType)); } } if (index > 0 && index + 1 < descriptor.Length) { Parameters = list; ReturnType = new JavaType(); if (descriptor[++index] == 'V') { return; } if (ReturnType.ParseType(descriptor, index) == descriptor.Length) { return; } } } throw Where.Exception($"bad method descriptor '{descriptor}'"); }
static void SetLocalInOneFrame(Frame frm, int index, JavaType type, JavaException.Where Where) { if (index < frm.locals.Count) { if (!frm.locals[index].Equals(type)) { if (Where != null && frm.locals[index] != Top) { throw Where.Exception($"local already assigned in stack frame"); } frm.locals[index] = type; } } else { while (index > frm.locals.Count) { frm.locals.Add(Top); } frm.locals.Add(type); } }
JavaWriter(Stream _stream, JavaClass _class) { Where = new JavaException.Where(); var memoryStream = new MemoryStream(); stream = memoryStream; forkedStreams = new Stack <Stream>(); constants = new JavaConstantPool(); _class.Write(this); stream = _stream; Write32(0xCAFEBABE); Write16(0); Write16(52); constants.Write(this); memoryStream.WriteTo(_stream); memoryStream.Dispose(); }
JavaReader(Stream _stream, string whereText, bool withCode) { Where = new JavaException.Where(); Where.Push(whereText); stream = _stream; if (Read32() != 0xCAFEBABE) { throw Where.Exception("bad class magic number"); } var(minorVersion, majorVersion) = (Read16(), Read16()); if (majorVersion < 45) { throw Where.Exception("bad class major version number"); } constants = new JavaConstantPool(this); new JavaClass(this, majorVersion, minorVersion, withCode); Where.Pop(); }
public void InitConstant(object value, JavaException.Where Where) { bool ok = false; if (Type.ArrayRank == 0 && (Flags & JavaAccessFlags.ACC_STATIC) != 0) { if ((Type.ClassName == "java.lang.String" && value is string) || (Type.PrimitiveType == TypeCode.Double && value is double) || (Type.PrimitiveType == TypeCode.Single && value is float) || (Type.PrimitiveType == TypeCode.Int64 && value is long)) { ok = true; } else if (Type.PrimitiveType == TypeCode.UInt64 && value is ulong) { value = (long)((ulong)value); ok = true; } else { switch (value) { case bool boolValue: value = (int)(boolValue ? 1 : 0); break; case byte byteValue: value = (int)byteValue; break; case sbyte sbyteValue: value = (int)sbyteValue; break; case char charValue: value = (int)charValue; break; case short shortValue: value = (int)shortValue; break; case ushort ushortValue: value = (int)ushortValue; break; case uint uintValue: value = (int)uintValue; break; } if (value is int) { if (Type.PrimitiveType == TypeCode.Boolean || Type.PrimitiveType == TypeCode.Byte || Type.PrimitiveType == TypeCode.SByte || Type.PrimitiveType == TypeCode.Char || Type.PrimitiveType == TypeCode.Int16 || Type.PrimitiveType == TypeCode.UInt16 || Type.PrimitiveType == TypeCode.Int32 || Type.PrimitiveType == TypeCode.UInt32) { ok = true; } } } } if (ok) { Constant = value; } else { throw Where.Exception($"bad constant value or non-static field of type '{Type}'"); } }
public JavaFieldRef(string name, string descriptor, JavaException.Where Where) { Name = name; Type = new JavaType(descriptor, Where); }
public JavaMethodRef(string descriptor, JavaException.Where Where) : base(descriptor, Where) { }
int[] MergeFrame(Frame old, ushort offsetLabel, JavaException.Where Where) { // // compare locals, with the exception that a 'top' type (in the // sense of an uninitialized local), which was already recorded // in one frame, may override a non-'top' type in the other // frame. this is the result of branching over // // ifnonnull L1 local 7 is uninitialized/'top' here // aload_1 assume local 1 is float // astore_7 local 7 is now initialized as float // L1: ... conflicting frames, and we keep 'top' // // note: if either frame contains more locals than the other // frame, we treat the missing locals as if they were defined // as a 'top' type (i.e. uninitialized) in the other frame. // List <int> resetLocals = null; var topLocals = top.locals; var oldLocals = old.locals; int topLocalsCount = topLocals.Count; int oldLocalsCount = oldLocals.Count; bool same = true; int iTop = 0; int iOld = 0; while (iTop < topLocalsCount || iOld < oldLocalsCount) { var oldElem = (iOld < oldLocalsCount) ? oldLocals[iOld] : Top; var topElem = (iTop < topLocalsCount) ? topLocals[iTop] : Top; if (!topElem.Equals(oldElem)) { if (oldElem.Equals(Top)) { topLocals[iTop] = topElem = Top; } else if (topElem.Equals(Top)) { oldLocals[iOld] = oldElem = Top; // report locals that were reset during merge if (resetLocals == null) { resetLocals = new List <int>(); } resetLocals.Add(iOld); } else if (!topElem.AssignableTo(oldElem)) { same = false; break; } } iTop += topElem.Category; iOld += oldElem.Category; } // // compare stacks, with the exception that a 'null' type, which // appears in one frame, may be overridden by a more specific // class type from the other frame, e.g. // // ifnonnull L1 stack is empty // aconst_null stack is [ null ] // goto L2 // L1. aload_1 if local 1 is string, stack is [ string ] // L2. ... conflicting frames, and we keep [ string ] // // note that the result would be the same even if 'aconst_null' // and 'aload_1'. and also note that 'uninitializedThis' is // treated in the same way as 'null'. // // a second exception is for assignability through the virtual // call to JavaType.AssignableTo. if an element from a stack is // assignable to the othe stack, then the other stack overrides. // for example, any reference can be assigned to java.lang.Object, // so a conflict is resolved by overriding with java.lang.Object. // var topStack = top.stack; var oldStack = old.stack; int numStack = topStack.Count; same &= (numStack == oldStack.Count); if (same) { for (int i = 0; i < numStack; i++) { var oldElem = oldStack[i]; var topElem = topStack[i]; if (!topElem.Equals(oldElem)) { if (oldElem.Equals(Null) || oldElem.Equals(UninitializedThis)) { oldStack[i] = topElem; } else if (topElem.Equals(Null) || topElem.Equals(UninitializedThis)) { topStack[i] = oldElem; } else if (oldElem.AssignableTo(topElem)) { oldStack[i] = topElem; } else if (topElem.AssignableTo(oldElem)) { topStack[i] = oldElem; } else if (old.branchTarget && (topElem = oldElem.ResolveConflict(topElem)) != null) { // the ternary operator ?: may produce code that causes a conflict: // object x = flag ? (object) new A() : (object) new B(); // if we detect such a conflict at a branch target, we assume this // is the cause, and set the stack elements to java.lang.Object oldStack[i] = topStack[i] = topElem; } else { same = false; break; } } } } if (!same) { #if DEBUGDIAG var(old1, old2) = FrameToString(offsetLabel); var(top1, top2) = FrameToString(); Console.WriteLine("old frame = " + old1 + " ; " + old2); Console.WriteLine("top frame = " + top1 + " ; " + top2); #endif throw Where.Exception($"conflicting stack frames at offset {offsetLabel:X4}"); } return((resetLocals != null) ? resetLocals.ToArray() : null); }