internal static bool Emit(DynamicTypeWrapper.FinishContext context, TypeWrapper wrapper, CodeEmitter ilgen, ClassFile classFile, int i, ClassFile.Method.Instruction[] code, InstructionFlags[] flags) { if (i >= 3 && (flags[i - 0] & InstructionFlags.BranchTarget) == 0 && (flags[i - 1] & InstructionFlags.BranchTarget) == 0 && (flags[i - 2] & InstructionFlags.BranchTarget) == 0 && (flags[i - 3] & InstructionFlags.BranchTarget) == 0 && code[i - 1].NormalizedOpCode == NormalizedByteCode.__ldc && code[i - 2].NormalizedOpCode == NormalizedByteCode.__ldc && code[i - 3].NormalizedOpCode == NormalizedByteCode.__ldc) { // we now have a structural match, now we need to make sure that the argument values are what we expect TypeWrapper tclass = classFile.GetConstantPoolClassType(code[i - 3].Arg1); TypeWrapper vclass = classFile.GetConstantPoolClassType(code[i - 2].Arg1); string fieldName = classFile.GetConstantPoolConstantString(code[i - 1].Arg1); if (tclass == wrapper && !vclass.IsUnloadable && !vclass.IsPrimitive && !vclass.IsNonPrimitiveValueType) { FieldWrapper field = wrapper.GetFieldWrapper(fieldName, vclass.SigName); if (field != null && !field.IsStatic && field.IsVolatile && field.DeclaringType == wrapper && field.FieldTypeWrapper == vclass) { // everything matches up, now call the actual emitter DoEmit(context, wrapper, ilgen, field); return true; } } } return false; }
/// <summary> /// Resolve this reference. /// </summary> public bool TryResolveClass(out ClassFile result) { if (resolvedClass == null) { DoTryResolveClass(out resolvedClass); } result = resolvedClass; return (result != null); }
/// <summary> /// Resolve this reference. /// </summary> public bool TryResolve(out ClassFile result) { if (resolved == null) { var type = Type as ObjectTypeReference; if (type != null) { Loader.TryLoadClass(Name, out resolved); } } result = resolved; return (result != null); }
/// <summary> /// Create the current type as class definition. /// </summary> protected virtual void CreateClassDefinition(Dex target, NameConverter nsConverter, ClassDefinition parent, ClassFile parentClass) { // Create classdef classDef = new ClassDefinition(); classDef.MapFileId = compiler.GetNextMapFileId(); classDef.Namespace = nsConverter.GetConvertedNamespace(typeDef); var name = NameConverter.GetConvertedName(typeDef); classDef.Name = (parent != null) ? parent.Name + "$" + name : name; // Set access flags //if (typeDef.IsPublic) classDef.IsPublic = true; //else classDef.IsPrivate = true; classDef.IsPublic = true; if (typeDef.IsFinal) { classDef.IsFinal = true; } if (typeDef.IsInterface) { classDef.IsInterface = true; classDef.IsAbstract = true; } else if (typeDef.IsAbstract) { classDef.IsAbstract = true; } if (typeDef.Interfaces.Any(x => x.ClassName == "java/lang/annotation/Annotation")) { classDef.IsAnnotation = true; } classDef.IsEnum = typeDef.IsEnum; if (parent != null) { // Add to parent if this is a nested type classDef.Owner = parent; parent.AddInnerClass(classDef); } else { // Add to dex if it is a root class target.AddClass(classDef); } }
/// <summary> /// Create the current type as class definition. /// </summary> protected void Create(Dex target, NameConverter nsConverter, ClassDefinition parent, ClassFile parentClass, XTypeDefinition parentXType) { xType = new XBuilder.JavaTypeDefinition(compiler.Module, parentXType, typeDef); CreateClassDefinition(target, nsConverter, parent, parentClass); CreateNestedClasses(target, nsConverter, parent); }
protected abstract void ValidateSig(ClassFile classFile, string descriptor);
protected override void ValidateSig(ClassFile classFile, string descriptor) { if(!IsValidMethodSig(descriptor)) { throw new ClassFormatError("{0} (Method \"{1}\" has invalid signature \"{2}\")", classFile.Name, this.Name, descriptor); } }
internal virtual void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { string descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, signature_index); if (descriptor == null || !IsValidMethodSig(descriptor)) { throw new ClassFormatError("Invalid MethodType signature"); } this.descriptor = String.Intern(descriptor.Replace('/', '.')); }
/// <summary> /// Default ctor /// </summary> internal JavaLangReflectConstructorBuilder(ClassFile cf) : base(cf, "System.Reflection.ConstructorInfo", "java/lang/reflect/Constructor") { }
private static Dictionary<int, string>[] FindLocalVariables(CodeInfo codeInfo, MethodWrapper mw, ClassFile classFile, ClassFile.Method method) { FindLocalVarState[] state = new FindLocalVarState[method.Instructions.Length]; state[0].changed = true; state[0].sites = new FindLocalVarStoreSite[method.MaxLocals]; TypeWrapper[] parameters = mw.GetParameters(); int argpos = 0; if (!mw.IsStatic) { state[0].sites[argpos++].Add(-1); } for (int i = 0; i < parameters.Length; i++) { state[0].sites[argpos++].Add(-1); if (parameters[i].IsWidePrimitive) { argpos++; } } return FindLocalVariablesImpl(codeInfo, classFile, method, state); }
protected override void CreateNestedTypes(ClassFile cf, Model.NetTypeDefinition declaringType, string parentFullName, Model.NetModule module, TargetFramework target) { // Do nothing }
/// <summary> /// Create type attributes /// </summary> protected override TypeAttributes GetAttributes(ClassFile cf) { return(TypeAttributes.NestedPublic | TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract); }
protected override void RegisterType(TargetFramework target, ClassFile classFile, Model.NetTypeDefinition typeDef) { // Do nothing }
/// <summary> /// Improve the type name for the given class. /// </summary> protected override string CreateTypeName(NetTypeDefinition declaringType, ClassFile classFile, string name, string @namespace) { return(base.CreateTypeName(declaringType, classFile, name, @namespace) + "Constants"); }
/// <summary> /// Default ctor /// </summary> public NestedInterfaceConstantsTypeBuilder(TypeBuilder parent, string parentFullName, ClassFile cf, InnerClass inner) : base(parent, parentFullName, cf, inner) { }
public static long timestamp( ClassFile file ) { Bard.log( "TODO: NativeFile::timestamp()" ); return 0; }
/// <summary> /// Default ctor /// </summary> internal JavaLangNoSuchFieldExceptionBuilder(ClassFile cf) : base(cf, "System.MissingFieldException", "java/lang/NoSuchFieldError") { }
public static java.lang.Class defineClass1(java.lang.ClassLoader thisClassLoader, string name, byte[] b, int off, int len, java.security.ProtectionDomain pd, string source) { // it appears the source argument is only used for trace messages in HotSpot. We'll just ignore it for now. Profiler.Enter("ClassLoader.defineClass"); try { try { ClassLoaderWrapper classLoaderWrapper = ClassLoaderWrapper.GetClassLoaderWrapper(thisClassLoader); ClassFile classFile = new ClassFile(b, off, len, name, classLoaderWrapper.ClassFileParseOptions, null); if (name != null && classFile.Name != name) { #if !FIRST_PASS throw new java.lang.NoClassDefFoundError(name + " (wrong name: " + classFile.Name + ")"); #endif } TypeWrapper type = classLoaderWrapper.DefineClass(classFile, pd); return type.ClassObject; } catch (RetargetableJavaException x) { throw x.ToJava(); } } finally { Profiler.Leave("ClassLoader.defineClass"); } }
/// <summary> /// Default ctor /// </summary> internal JavaLangComparableBuilder(ClassFile cf) : base(cf, "System.Comparable", "java/lang/Comparable") { }
private static void VisitLocalLoads(CodeInfo codeInfo, ClassFile.Method method, List<LocalVar> locals, Dictionary<long, LocalVar> localByStoreSite, Dictionary<int, string> storeSites, int instructionIndex, bool debug) { Debug.Assert(IsLoadLocal(method.Instructions[instructionIndex].NormalizedOpCode)); LocalVar local = null; TypeWrapper type = VerifierTypeWrapper.Null; int localIndex = method.Instructions[instructionIndex].NormalizedArg1; bool isArg = false; foreach (int store in storeSites.Keys) { if (store == -1) { // it's a method argument, it has no initial store, but the type is simply the parameter type type = InstructionState.FindCommonBaseType(type, codeInfo.GetLocalTypeWrapper(0, localIndex)); isArg = true; } else { if (method.Instructions[store].NormalizedOpCode == NormalizedByteCode.__invokespecial) { type = InstructionState.FindCommonBaseType(type, codeInfo.GetLocalTypeWrapper(store + 1, localIndex)); } else if (method.Instructions[store].NormalizedOpCode == NormalizedByteCode.__static_error) { // it's an __invokespecial that turned into a __static_error // (since a __static_error doesn't continue, we don't need to set type) } else { Debug.Assert(IsStoreLocal(method.Instructions[store].NormalizedOpCode)); type = InstructionState.FindCommonBaseType(type, codeInfo.GetStackTypeWrapper(store, 0)); } } // we can't have an invalid type, because that would have failed verification earlier Debug.Assert(type != VerifierTypeWrapper.Invalid); LocalVar l; if (localByStoreSite.TryGetValue(MakeKey(store, localIndex), out l)) { if (local == null) { local = l; } else if (local != l) { // If we've already defined a LocalVar and we find another one, then we merge them // together. // This happens for the following code fragment: // // int i = -1; // try { i = 0; for(; ; ) System.out.println(i); } catch(Exception x) {} // try { i = 0; for(; ; ) System.out.println(i); } catch(Exception x) {} // System.out.println(i); // local = MergeLocals(locals, localByStoreSite, local, l); } } } if (local == null) { local = new LocalVar(); local.local = localIndex; if (VerifierTypeWrapper.IsThis(type)) { local.type = ((VerifierTypeWrapper)type).UnderlyingType; } else { local.type = type; } local.isArg = isArg; if (debug) { FindLvtEntry(local, method, instructionIndex); } locals.Add(local); } else { local.isArg |= isArg; local.type = InstructionState.FindCommonBaseType(local.type, type); Debug.Assert(local.type != VerifierTypeWrapper.Invalid); } foreach (int store in storeSites.Keys) { LocalVar v; if (!localByStoreSite.TryGetValue(MakeKey(store, localIndex), out v)) { localByStoreSite[MakeKey(store, localIndex)] = local; } else if (v != local) { local = MergeLocals(locals, localByStoreSite, local, v); } } }
protected override string GetContent(Task task, ClassFile classFile) { return(Dao.Factory.ClassFileDao.GivenTypesFileContents(task, classFile)); }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { if(classFile.GetConstantPoolUtf8String(utf8_cp, name_index) == null || classFile.GetConstantPoolUtf8String(utf8_cp, descriptor_index) == null) { throw new ClassFormatError("Illegal constant pool index"); } }
public GivenTypeFile(Task parent, ClassFile source) : base(parent, source) { }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { s = classFile.GetConstantPoolUtf8String(utf8_cp, string_index); }
/// <summary> /// Default ctor /// </summary> internal JavaLangFloatBuilder(ClassFile cf) : base(cf, "System.Single", "java/lang/Float") { }
private void DecodePropertyAnnotation(ClassFile classFile, object[] annot) { if(propertyGetterSetter != null) { Tracer.Error(Tracer.ClassLoading, "Ignoring duplicate ikvm.lang.Property annotation on {0}.{1}", classFile.Name, this.Name); return; } propertyGetterSetter = new string[2]; for(int i = 2; i < annot.Length - 1; i += 2) { string value = annot[i + 1] as string; if(value == null) { propertyGetterSetter = null; break; } if(annot[i].Equals("get") && propertyGetterSetter[0] == null) { propertyGetterSetter[0] = value; } else if(annot[i].Equals("set") && propertyGetterSetter[1] == null) { propertyGetterSetter[1] = value; } else { propertyGetterSetter = null; break; } } if(propertyGetterSetter == null || propertyGetterSetter[0] == null) { propertyGetterSetter = null; Tracer.Error(Tracer.ClassLoading, "Ignoring malformed ikvm.lang.Property annotation on {0}.{1}", classFile.Name, this.Name); return; } }
/// <summary> /// Create a type builder for the given type. /// </summary> internal static ClassBuilder Create(AssemblyCompiler compiler, ClassFile typeDef) { return(new StandardClassBuilder(compiler, typeDef)); }
internal void Read(ushort pc, BigEndianBinaryReader br, ClassFile classFile) { this.pc = pc; ByteCode bc = (ByteCode)br.ReadByte(); switch(ByteCodeMetaData.GetMode(bc)) { case ByteCodeMode.Simple: break; case ByteCodeMode.Constant_1: arg1 = br.ReadByte(); classFile.MarkLinkRequiredConstantPoolItem(arg1); break; case ByteCodeMode.Local_1: arg1 = br.ReadByte(); break; case ByteCodeMode.Constant_2: arg1 = br.ReadUInt16(); classFile.MarkLinkRequiredConstantPoolItem(arg1); break; case ByteCodeMode.Branch_2: arg1 = br.ReadInt16(); break; case ByteCodeMode.Branch_4: arg1 = br.ReadInt32(); break; case ByteCodeMode.Constant_2_1_1: arg1 = br.ReadUInt16(); classFile.MarkLinkRequiredConstantPoolItem(arg1); arg2 = br.ReadByte(); if(br.ReadByte() != 0) { throw new ClassFormatError("invokeinterface filler must be zero"); } break; case ByteCodeMode.Immediate_1: arg1 = br.ReadSByte(); break; case ByteCodeMode.Immediate_2: arg1 = br.ReadInt16(); break; case ByteCodeMode.Local_1_Immediate_1: arg1 = br.ReadByte(); arg2 = br.ReadSByte(); break; case ByteCodeMode.Constant_2_Immediate_1: arg1 = br.ReadUInt16(); classFile.MarkLinkRequiredConstantPoolItem(arg1); arg2 = br.ReadSByte(); break; case ByteCodeMode.Tableswitch: { // skip the padding uint p = pc + 1u; uint align = ((p + 3) & 0x7ffffffc) - p; br.Skip(align); int default_offset = br.ReadInt32(); this.arg1 = default_offset; int low = br.ReadInt32(); int high = br.ReadInt32(); if(low > high || high > 16384L + low) { throw new ClassFormatError("Incorrect tableswitch"); } SwitchEntry[] entries = new SwitchEntry[high - low + 1]; for(int i = low; i < high; i++) { entries[i - low].value = i; entries[i - low].target = br.ReadInt32(); } // do the last entry outside the loop, to avoid overflowing "i", if high == int.MaxValue entries[high - low].value = high; entries[high - low].target = br.ReadInt32(); this.switch_entries = entries; break; } case ByteCodeMode.Lookupswitch: { // skip the padding uint p = pc + 1u; uint align = ((p + 3) & 0x7ffffffc) - p; br.Skip(align); int default_offset = br.ReadInt32(); this.arg1 = default_offset; int count = br.ReadInt32(); if(count < 0 || count > 16384) { throw new ClassFormatError("Incorrect lookupswitch"); } SwitchEntry[] entries = new SwitchEntry[count]; for(int i = 0; i < count; i++) { entries[i].value = br.ReadInt32(); entries[i].target = br.ReadInt32(); } this.switch_entries = entries; break; } case ByteCodeMode.WidePrefix: bc = (ByteCode)br.ReadByte(); // NOTE the PC of a wide instruction is actually the PC of the // wide prefix, not the following instruction (vmspec 4.9.2) switch(ByteCodeMetaData.GetWideMode(bc)) { case ByteCodeModeWide.Local_2: arg1 = br.ReadUInt16(); break; case ByteCodeModeWide.Local_2_Immediate_2: arg1 = br.ReadUInt16(); arg2 = br.ReadInt16(); break; default: throw new ClassFormatError("Invalid wide prefix on opcode: {0}", bc); } break; default: throw new ClassFormatError("Invalid opcode: {0}", bc); } this.normopcode = ByteCodeMetaData.GetNormalizedByteCode(bc); arg1 = ByteCodeMetaData.GetArg(bc, arg1); }
public static void native_mkdir( ClassFile file ) { Bard.log( "TODO: NativeFile::native_mkdir()" ); }
private static Dictionary <int, string>[] FindLocalVariables(CodeInfo codeInfo, MethodWrapper mw, ClassFile classFile, ClassFile.Method method) { FindLocalVarState[] state = new FindLocalVarState[method.Instructions.Length]; state[0].changed = true; state[0].sites = new FindLocalVarStoreSite[method.MaxLocals]; TypeWrapper[] parameters = mw.GetParameters(); int argpos = 0; if (!mw.IsStatic) { state[0].sites[argpos++].Add(-1); } for (int i = 0; i < parameters.Length; i++) { state[0].sites[argpos++].Add(-1); if (parameters[i].IsWidePrimitive) { argpos++; } } return(FindLocalVariablesImpl(codeInfo, classFile, method, state)); }
/// <summary> /// Default ctor /// </summary> protected ClassBuilder(AssemblyCompiler compiler, ClassFile typeDef) { this.compiler = compiler; this.typeDef = typeDef; }
public static bool is_directory( ClassFile file ) { Bard.log( "TODO: NativeFile::is_directory()" ); return false; }
private static Dictionary <int, string>[] FindLocalVariablesImpl(CodeInfo codeInfo, ClassFile classFile, ClassFile.Method method, FindLocalVarState[] state) { ClassFile.Method.Instruction[] instructions = method.Instructions; ExceptionTableEntry[] exceptions = method.ExceptionTable; int maxLocals = method.MaxLocals; Dictionary <int, string>[] localStoreReaders = new Dictionary <int, string> [instructions.Length]; bool done = false; while (!done) { done = true; for (int i = 0; i < instructions.Length; i++) { if (state[i].changed) { done = false; state[i].changed = false; FindLocalVarState curr = state[i].Copy(); for (int j = 0; j < exceptions.Length; j++) { if (exceptions[j].startIndex <= i && i < exceptions[j].endIndex) { state[exceptions[j].handlerIndex].Merge(curr); } } if (IsLoadLocal(instructions[i].NormalizedOpCode) && (instructions[i].NormalizedOpCode != NormalizedByteCode.__aload || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i + 1, 0)))) { if (localStoreReaders[i] == null) { localStoreReaders[i] = new Dictionary <int, string>(); } for (int j = 0; j < curr.sites[instructions[i].NormalizedArg1].Count; j++) { localStoreReaders[i][curr.sites[instructions[i].NormalizedArg1][j]] = ""; } } if (IsStoreLocal(instructions[i].NormalizedOpCode) && (instructions[i].NormalizedOpCode != NormalizedByteCode.__astore || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i, 0)))) { curr.Store(i, instructions[i].NormalizedArg1); // if this is a store at the end of an exception block, // we need to propagate the new state to the exception handler for (int j = 0; j < exceptions.Length; j++) { if (exceptions[j].endIndex == i + 1) { state[exceptions[j].handlerIndex].Merge(curr); } } } if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial) { ClassFile.ConstantPoolItemMI cpi = classFile.GetMethodref(instructions[i].Arg1); if (ReferenceEquals(cpi.Name, StringConstants.INIT)) { TypeWrapper type = codeInfo.GetRawStackTypeWrapper(i, cpi.GetArgTypes().Length); // after we've invoked the constructor, the uninitialized references // are now initialized if (type == VerifierTypeWrapper.UninitializedThis || VerifierTypeWrapper.IsNew(type)) { for (int j = 0; j < maxLocals; j++) { if (codeInfo.GetLocalTypeWrapper(i, j) == type) { curr.Store(i, j); } } } } } else if (instructions[i].NormalizedOpCode == NormalizedByteCode.__goto_finally) { int handler = instructions[i].HandlerIndex; // Normally a store at the end of a try block doesn't affect the handler block, // but in the case of a finally handler it does, so we need to make sure that // we merge here in case the try block ended with a store. state[handler].Merge(curr); // Now we recursively analyse the handler and afterwards merge the endfault locations back to us FindLocalVarState[] handlerState = new FindLocalVarState[instructions.Length]; handlerState[handler].Merge(curr); curr = new FindLocalVarState(); FindLocalVariablesImpl(codeInfo, classFile, method, handlerState); // Merge back to the target of our __goto_finally for (int j = 0; j < handlerState.Length; j++) { if (instructions[j].NormalizedOpCode == NormalizedByteCode.__athrow && codeInfo.HasState(j) && VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(j, 0)) && ((VerifierTypeWrapper)codeInfo.GetRawStackTypeWrapper(j, 0)).Index == handler) { curr.Merge(handlerState[j]); } } } switch (ByteCodeMetaData.GetFlowControl(instructions[i].NormalizedOpCode)) { case ByteCodeFlowControl.Switch: { for (int j = 0; j < instructions[i].SwitchEntryCount; j++) { state[instructions[i].GetSwitchTargetIndex(j)].Merge(curr); } state[instructions[i].DefaultTarget].Merge(curr); break; } case ByteCodeFlowControl.Branch: state[instructions[i].TargetIndex].Merge(curr); break; case ByteCodeFlowControl.CondBranch: state[instructions[i].TargetIndex].Merge(curr); state[i + 1].Merge(curr); break; case ByteCodeFlowControl.Return: case ByteCodeFlowControl.Throw: break; case ByteCodeFlowControl.Next: state[i + 1].Merge(curr); break; default: throw new InvalidOperationException(); } } } } return(localStoreReaders); }
public static void rename( ClassFile file, ClassString new_name ) { Bard.log( "TODO: NativeFile::rename()" ); }
internal LocalVarInfo(CodeInfo ma, ClassFile classFile, ClassFile.Method method, UntangledExceptionTable exceptions, MethodWrapper mw, ClassLoaderWrapper classLoader) { Dictionary <int, string>[] localStoreReaders = FindLocalVariables(ma, mw, classFile, method); // now that we've done the code flow analysis, we can do a liveness analysis on the local variables ClassFile.Method.Instruction[] instructions = method.Instructions; Dictionary <long, LocalVar> localByStoreSite = new Dictionary <long, LocalVar>(); List <LocalVar> locals = new List <LocalVar>(); for (int i = 0; i < localStoreReaders.Length; i++) { if (localStoreReaders[i] != null) { VisitLocalLoads(ma, method, locals, localByStoreSite, localStoreReaders[i], i, classLoader.EmitDebugInfo); } } Dictionary <LocalVar, LocalVar> forwarders = new Dictionary <LocalVar, LocalVar>(); if (classLoader.EmitDebugInfo) { InstructionFlags[] flags = MethodAnalyzer.ComputePartialReachability(ma, method.Instructions, exceptions, 0, false); // if we're emitting debug info, we need to keep dead stores as well... for (int i = 0; i < instructions.Length; i++) { if ((flags[i] & InstructionFlags.Reachable) != 0 && IsStoreLocal(instructions[i].NormalizedOpCode)) { if (!localByStoreSite.ContainsKey(MakeKey(i, instructions[i].NormalizedArg1))) { LocalVar v = new LocalVar(); v.local = instructions[i].NormalizedArg1; v.type = ma.GetStackTypeWrapper(i, 0); FindLvtEntry(v, method, i); locals.Add(v); localByStoreSite.Add(MakeKey(i, v.local), v); } } } // to make the debugging experience better, we have to trust the // LocalVariableTable (unless it's clearly bogus) and merge locals // together that are the same according to the LVT for (int i = 0; i < locals.Count - 1; i++) { for (int j = i + 1; j < locals.Count; j++) { LocalVar v1 = (LocalVar)locals[i]; LocalVar v2 = (LocalVar)locals[j]; if (v1.name != null && v1.name == v2.name && v1.start_pc == v2.start_pc && v1.end_pc == v2.end_pc) { // we can only merge if the resulting type is valid (this protects against incorrect // LVT data, but is also needed for constructors, where the uninitialized this is a different // type from the initialized this) TypeWrapper tw = InstructionState.FindCommonBaseType(v1.type, v2.type); if (tw != VerifierTypeWrapper.Invalid) { v1.isArg |= v2.isArg; v1.type = tw; forwarders.Add(v2, v1); locals.RemoveAt(j); j--; } } } } } else { for (int i = 0; i < locals.Count - 1; i++) { for (int j = i + 1; j < locals.Count; j++) { LocalVar v1 = (LocalVar)locals[i]; LocalVar v2 = (LocalVar)locals[j]; // if the two locals are the same, we merge them, this is a small // optimization, it should *not* be required for correctness. if (v1.local == v2.local && v1.type == v2.type) { v1.isArg |= v2.isArg; forwarders.Add(v2, v1); locals.RemoveAt(j); j--; } } } } invokespecialLocalVars = new LocalVar[instructions.Length][]; localVars = new LocalVar[instructions.Length]; for (int i = 0; i < localVars.Length; i++) { LocalVar v = null; if (localStoreReaders[i] != null) { Debug.Assert(IsLoadLocal(instructions[i].NormalizedOpCode)); // lame way to look up the local variable for a load // (by indirecting through a corresponding store) foreach (int store in localStoreReaders[i].Keys) { v = localByStoreSite[MakeKey(store, instructions[i].NormalizedArg1)]; break; } } else { if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial || instructions[i].NormalizedOpCode == NormalizedByteCode.__dynamic_invokespecial) { invokespecialLocalVars[i] = new LocalVar[method.MaxLocals]; for (int j = 0; j < invokespecialLocalVars[i].Length; j++) { localByStoreSite.TryGetValue(MakeKey(i, j), out invokespecialLocalVars[i][j]); } } else { localByStoreSite.TryGetValue(MakeKey(i, instructions[i].NormalizedArg1), out v); } } if (v != null) { LocalVar fwd; if (forwarders.TryGetValue(v, out fwd)) { v = fwd; } localVars[i] = v; } } this.allLocalVars = locals.ToArray(); }
public static void touch( ClassFile file ) { Bard.log( "TODO: NativeFile::touch()" ); }
/// <summary> /// Default ctor /// </summary> internal JavaLangClassBuilder(ClassFile cf) : base(cf, "System.Type", "java/lang/Class") { }
private static void FindLvtEntry(LocalVar lv, ClassFile.Method method, int instructionIndex) { ClassFile.Method.LocalVariableTableEntry[] lvt = method.LocalVariableTableAttribute; if (lvt != null) { int pc = method.Instructions[instructionIndex].PC; int nextPC = method.Instructions[instructionIndex + 1].PC; bool isStore = IsStoreLocal(method.Instructions[instructionIndex].NormalizedOpCode); foreach (ClassFile.Method.LocalVariableTableEntry e in lvt) { // TODO validate the contents of the LVT entry if (e.index == lv.local && (e.start_pc <= pc || (e.start_pc == nextPC && isStore)) && e.start_pc + e.length > pc) { lv.name = e.name; lv.start_pc = e.start_pc; lv.end_pc = e.start_pc + e.length; break; } } } }
protected virtual void AddGenericRepositoryParameter(ClassFile classFile) { classFile.Constructor.AddFieldWithParameter(new Field("private", "_genericRepository", $"IGenericRepository<{GetEntityName}>"), new TypeWithName("genericRepository", $"IGenericRepository<{GetEntityName}>")); }
private static Dictionary<int, string>[] FindLocalVariablesImpl(CodeInfo codeInfo, ClassFile classFile, ClassFile.Method method, FindLocalVarState[] state) { ClassFile.Method.Instruction[] instructions = method.Instructions; ExceptionTableEntry[] exceptions = method.ExceptionTable; int maxLocals = method.MaxLocals; Dictionary<int, string>[] localStoreReaders = new Dictionary<int, string>[instructions.Length]; bool done = false; while (!done) { done = true; for (int i = 0; i < instructions.Length; i++) { if (state[i].changed) { done = false; state[i].changed = false; FindLocalVarState curr = state[i].Copy(); for (int j = 0; j < exceptions.Length; j++) { if (exceptions[j].startIndex <= i && i < exceptions[j].endIndex) { state[exceptions[j].handlerIndex].Merge(curr); } } if (IsLoadLocal(instructions[i].NormalizedOpCode) && (instructions[i].NormalizedOpCode != NormalizedByteCode.__aload || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i + 1, 0)))) { if (localStoreReaders[i] == null) { localStoreReaders[i] = new Dictionary<int, string>(); } for (int j = 0; j < curr.sites[instructions[i].NormalizedArg1].Count; j++) { localStoreReaders[i][curr.sites[instructions[i].NormalizedArg1][j]] = ""; } } if (IsStoreLocal(instructions[i].NormalizedOpCode) && (instructions[i].NormalizedOpCode != NormalizedByteCode.__astore || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i, 0)))) { curr.Store(i, instructions[i].NormalizedArg1); // if this is a store at the end of an exception block, // we need to propagate the new state to the exception handler for (int j = 0; j < exceptions.Length; j++) { if (exceptions[j].endIndex == i + 1) { state[exceptions[j].handlerIndex].Merge(curr); } } } if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial) { ClassFile.ConstantPoolItemMI cpi = classFile.GetMethodref(instructions[i].Arg1); if (ReferenceEquals(cpi.Name, StringConstants.INIT)) { TypeWrapper type = codeInfo.GetRawStackTypeWrapper(i, cpi.GetArgTypes().Length); // after we've invoked the constructor, the uninitialized references // are now initialized if (type == VerifierTypeWrapper.UninitializedThis || VerifierTypeWrapper.IsNew(type)) { for (int j = 0; j < maxLocals; j++) { if (codeInfo.GetLocalTypeWrapper(i, j) == type) { curr.Store(i, j); } } } } } else if (instructions[i].NormalizedOpCode == NormalizedByteCode.__goto_finally) { int handler = instructions[i].HandlerIndex; // Normally a store at the end of a try block doesn't affect the handler block, // but in the case of a finally handler it does, so we need to make sure that // we merge here in case the try block ended with a store. state[handler].Merge(curr); // Now we recursively analyse the handler and afterwards merge the endfault locations back to us FindLocalVarState[] handlerState = new FindLocalVarState[instructions.Length]; handlerState[handler].Merge(curr); curr = new FindLocalVarState(); FindLocalVariablesImpl(codeInfo, classFile, method, handlerState); // Merge back to the target of our __goto_finally for (int j = 0; j < handlerState.Length; j++) { if (instructions[j].NormalizedOpCode == NormalizedByteCode.__athrow && codeInfo.HasState(j) && VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(j, 0)) && ((VerifierTypeWrapper)codeInfo.GetRawStackTypeWrapper(j, 0)).Index == handler) { curr.Merge(handlerState[j]); } } } switch (ByteCodeMetaData.GetFlowControl(instructions[i].NormalizedOpCode)) { case ByteCodeFlowControl.Switch: { for (int j = 0; j < instructions[i].SwitchEntryCount; j++) { state[instructions[i].GetSwitchTargetIndex(j)].Merge(curr); } state[instructions[i].DefaultTarget].Merge(curr); break; } case ByteCodeFlowControl.Branch: state[instructions[i].TargetIndex].Merge(curr); break; case ByteCodeFlowControl.CondBranch: state[instructions[i].TargetIndex].Merge(curr); state[i + 1].Merge(curr); break; case ByteCodeFlowControl.Return: case ByteCodeFlowControl.Throw: break; case ByteCodeFlowControl.Next: state[i + 1].Merge(curr); break; default: throw new InvalidOperationException(); } } } } return localStoreReaders; }
/// <summary> /// Try to load a class from import mappings. /// </summary> bool IClassLoader.TryLoadClass(string className, out ClassFile result) { return(assemblyClassLoader.TryLoadClass(className, out result)); }
internal LocalVarInfo(CodeInfo ma, ClassFile classFile, ClassFile.Method method, UntangledExceptionTable exceptions, MethodWrapper mw, ClassLoaderWrapper classLoader) { Dictionary<int, string>[] localStoreReaders = FindLocalVariables(ma, mw, classFile, method); // now that we've done the code flow analysis, we can do a liveness analysis on the local variables ClassFile.Method.Instruction[] instructions = method.Instructions; Dictionary<long, LocalVar> localByStoreSite = new Dictionary<long, LocalVar>(); List<LocalVar> locals = new List<LocalVar>(); for (int i = 0; i < localStoreReaders.Length; i++) { if (localStoreReaders[i] != null) { VisitLocalLoads(ma, method, locals, localByStoreSite, localStoreReaders[i], i, classLoader.EmitDebugInfo); } } Dictionary<LocalVar, LocalVar> forwarders = new Dictionary<LocalVar, LocalVar>(); if (classLoader.EmitDebugInfo) { InstructionFlags[] flags = MethodAnalyzer.ComputePartialReachability(ma, method.Instructions, exceptions, 0, false); // if we're emitting debug info, we need to keep dead stores as well... for (int i = 0; i < instructions.Length; i++) { if ((flags[i] & InstructionFlags.Reachable) != 0 && IsStoreLocal(instructions[i].NormalizedOpCode)) { if (!localByStoreSite.ContainsKey(MakeKey(i, instructions[i].NormalizedArg1))) { LocalVar v = new LocalVar(); v.local = instructions[i].NormalizedArg1; v.type = ma.GetStackTypeWrapper(i, 0); FindLvtEntry(v, method, i); locals.Add(v); localByStoreSite.Add(MakeKey(i, v.local), v); } } } // to make the debugging experience better, we have to trust the // LocalVariableTable (unless it's clearly bogus) and merge locals // together that are the same according to the LVT for (int i = 0; i < locals.Count - 1; i++) { for (int j = i + 1; j < locals.Count; j++) { LocalVar v1 = (LocalVar)locals[i]; LocalVar v2 = (LocalVar)locals[j]; if (v1.name != null && v1.name == v2.name && v1.start_pc == v2.start_pc && v1.end_pc == v2.end_pc) { // we can only merge if the resulting type is valid (this protects against incorrect // LVT data, but is also needed for constructors, where the uninitialized this is a different // type from the initialized this) TypeWrapper tw = InstructionState.FindCommonBaseType(v1.type, v2.type); if (tw != VerifierTypeWrapper.Invalid) { v1.isArg |= v2.isArg; v1.type = tw; forwarders.Add(v2, v1); locals.RemoveAt(j); j--; } } } } } else { for (int i = 0; i < locals.Count - 1; i++) { for (int j = i + 1; j < locals.Count; j++) { LocalVar v1 = (LocalVar)locals[i]; LocalVar v2 = (LocalVar)locals[j]; // if the two locals are the same, we merge them, this is a small // optimization, it should *not* be required for correctness. if (v1.local == v2.local && v1.type == v2.type) { v1.isArg |= v2.isArg; forwarders.Add(v2, v1); locals.RemoveAt(j); j--; } } } } invokespecialLocalVars = new LocalVar[instructions.Length][]; localVars = new LocalVar[instructions.Length]; for (int i = 0; i < localVars.Length; i++) { LocalVar v = null; if (localStoreReaders[i] != null) { Debug.Assert(IsLoadLocal(instructions[i].NormalizedOpCode)); // lame way to look up the local variable for a load // (by indirecting through a corresponding store) foreach (int store in localStoreReaders[i].Keys) { v = localByStoreSite[MakeKey(store, instructions[i].NormalizedArg1)]; break; } } else { if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial) { invokespecialLocalVars[i] = new LocalVar[method.MaxLocals]; for (int j = 0; j < invokespecialLocalVars[i].Length; j++) { localByStoreSite.TryGetValue(MakeKey(i, j), out invokespecialLocalVars[i][j]); } } else { localByStoreSite.TryGetValue(MakeKey(i, instructions[i].NormalizedArg1), out v); } } if (v != null) { LocalVar fwd; if (forwarders.TryGetValue(v, out fwd)) { v = fwd; } localVars[i] = v; } } this.allLocalVars = locals.ToArray(); }
public void Test() { var cf = new ClassFile(new MemoryStream(Resources.HalloAndroidActivity), null); Assert.AreEqual("org/hello/HalloAndroidActivity", cf.ClassName); }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { name = classFile.GetConstantPoolUtf8String(utf8_cp, name_index); if(name.Length > 0) { // We don't enforce the strict class name rules in the static compiler, since HotSpot doesn't enforce *any* rules on // class names for the system (and boot) class loader. We still need to enforce the 1.5 restrictions, because we // rely on those invariants. #if !STATIC_COMPILER if(classFile.MajorVersion < 49 && (options & ClassFileParseOptions.RelaxedClassNameValidation) == 0) { char prev = name[0]; if(Char.IsLetter(prev) || prev == '$' || prev == '_' || prev == '[' || prev == '/') { int skip = 1; int end = name.Length; if(prev == '[') { if(!IsValidFieldSig(name)) { goto barf; } while(name[skip] == '[') { skip++; } if(name.EndsWith(";")) { end--; } } for(int i = skip; i < end; i++) { char c = name[i]; if(!Char.IsLetterOrDigit(c) && c != '$' && c != '_' && (c != '/' || prev == '/')) { goto barf; } prev = c; } name = String.Intern(name.Replace('/', '.')); return; } } else #endif { // since 1.5 the restrictions on class names have been greatly reduced int end = name.Length; if(name[0] == '[') { if(!IsValidFieldSig(name)) { goto barf; } // the semicolon is only allowed at the end and IsValidFieldSig enforces this, // but since invalidJava15Characters contains the semicolon, we decrement end // to make the following check against invalidJava15Characters ignore the // trailing semicolon. if(name[end - 1] == ';') { end--; } } if(name.IndexOfAny(invalidJava15Characters, 0, end) >= 0) { goto barf; } name = String.Intern(name.Replace('/', '.')); return; } } barf: throw new ClassFormatError("Invalid class name \"{0}\"", name); }
/// <summary> /// Default ctor /// </summary> internal JavaLangMathBuilder(ClassFile cf) : base(cf, "System.Math", "java/lang/Math") { }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { switch ((RefKind)ref_kind) { case RefKind.getField: case RefKind.getStatic: case RefKind.putField: case RefKind.putStatic: cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemFieldref; break; case RefKind.invokeSpecial: case RefKind.invokeVirtual: case RefKind.invokeStatic: case RefKind.newInvokeSpecial: cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemMethodref; break; case RefKind.invokeInterface: cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemInterfaceMethodref; break; } if (cpi == null) { throw new ClassFormatError("Invalid constant pool item MethodHandle"); } if (ReferenceEquals(cpi.Name, StringConstants.INIT) && Kind != RefKind.newInvokeSpecial) { throw new ClassFormatError("Bad method name"); } }
/// <summary> /// Default ctor /// </summary> internal JavaLangArrayStoreExceptionBuilder(ClassFile cf) : base(cf, "System.ArrayTypeMismatchException", "java/lang/ArrayStoreException") { }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { ConstantPoolItemNameAndType name_and_type = (ConstantPoolItemNameAndType)classFile.GetConstantPoolItem(name_and_type_index); // if the constant pool items referred to were strings, GetConstantPoolItem returns null if (name_and_type == null) { throw new ClassFormatError("Bad index in constant pool"); } name = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.name_index)); descriptor = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.descriptor_index).Replace('/', '.')); }
//void ShowUnknownGUI() //{ // EditorGUILayout.Space(); // showUnknownFoldout = GUILayoutHelper.Foldout(showUnknownFoldout, new GUIContent("Unknown"), () => // { // EditorGUILayout.Space(); // GUILayoutHelper.Indent(() => // { // EditorGUILayout.LabelField("Unknown1 [1 Bytes]"); // EditorGUILayout.SelectableLabel(selectedCareer.RawData.Unknown1.ToString("X2"), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); // }); // GUILayoutHelper.Indent(() => // { // EditorGUILayout.LabelField("Unknown2 [8 Bytes]"); // string valuesString = string.Empty; // for (int i = 0; i < selectedCareer.RawData.Unknown2.Length; i++) // { // valuesString += selectedCareer.RawData.Unknown2[i].ToString("X2") + " "; // } // EditorGUILayout.SelectableLabel(valuesString, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); // }); // }); //} bool IsReady() { dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady || string.IsNullOrEmpty(dfUnity.Arena2Path)) { return(false); } // Read all CLASS*.CFG files if (classTemplates == null) { string[] files = Directory.GetFiles(dfUnity.Arena2Path, "class*.cfg"); if (files != null && files.Length > 0) { classTemplates = new DFCareer[files.Length - 1]; classNames = new GUIContent[files.Length - 1]; for (int i = 0; i < files.Length - 1; i++) { ClassFile classFile = new ClassFile(files[i]); classTemplates[i] = classFile.Career; classNames[i] = new GUIContent(classTemplates[i].Name); } } } // Read all ENEMY*.CFG files if (monsterTemplates == null) { MonsterFile monsterFile = new MonsterFile(); if (monsterFile.Load(Path.Combine(dfUnity.Arena2Path, MonsterFile.Filename), FileUsage.UseMemory, true)) { // First pass locates CFG record indices List <int> cfgIndices = new List <int>(); for (int i = 0; i < monsterFile.Count; i++) { string recordName = monsterFile.GetRecordName(i); if (recordName.EndsWith(".cfg", StringComparison.InvariantCultureIgnoreCase)) { cfgIndices.Add(i); } } // Second pass populates arrays monsterTemplates = new DFCareer[cfgIndices.Count]; monsterNames = new GUIContent[cfgIndices.Count]; for (int i = 0; i < cfgIndices.Count; i++) { // Read ENEMY.CFG class file from stream ClassFile classFile = new ClassFile(); byte[] data = monsterFile.GetRecordBytes(cfgIndices[i]); MemoryStream stream = new MemoryStream(data); BinaryReader reader = new BinaryReader(stream); classFile.Load(reader); reader.Close(); // Add to arrays monsterTemplates[i] = classFile.Career; monsterNames[i] = new GUIContent(monsterTemplates[i].Name); } } else { return(false); } } return(true); }
internal FieldOrMethod(ClassFile classFile, string[] utf8_cp, BigEndianBinaryReader br) { access_flags = (Modifiers)br.ReadUInt16(); name = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())); descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); ValidateSig(classFile, descriptor); descriptor = String.Intern(descriptor.Replace('/', '.')); }
/// <summary> /// Default ctor /// </summary> internal AndroidAppActivityBuilder(ClassFile cf) : base(cf, "android/app/Activity") { }
internal Field(ClassFile classFile, string[] utf8_cp, BigEndianBinaryReader br) : base(classFile, utf8_cp, br) { if((IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected) || (IsFinal && IsVolatile) || (classFile.IsInterface && (!IsPublic || !IsStatic || !IsFinal || IsTransient))) { throw new ClassFormatError("{0} (Illegal field modifiers: 0x{1:X})", classFile.Name, access_flags); } int attributes_count = br.ReadUInt16(); for(int i = 0; i < attributes_count; i++) { switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) { case "Deprecated": if(br.ReadUInt32() != 0) { throw new ClassFormatError("Invalid Deprecated attribute length"); } flags |= FLAG_MASK_DEPRECATED; break; case "ConstantValue": { if(br.ReadUInt32() != 2) { throw new ClassFormatError("Invalid ConstantValue attribute length"); } ushort index = br.ReadUInt16(); try { switch(Signature) { case "I": constantValue = classFile.GetConstantPoolConstantInteger(index); break; case "S": constantValue = (short)classFile.GetConstantPoolConstantInteger(index); break; case "B": constantValue = (byte)classFile.GetConstantPoolConstantInteger(index); break; case "C": constantValue = (char)classFile.GetConstantPoolConstantInteger(index); break; case "Z": constantValue = classFile.GetConstantPoolConstantInteger(index) != 0; break; case "J": constantValue = classFile.GetConstantPoolConstantLong(index); break; case "F": constantValue = classFile.GetConstantPoolConstantFloat(index); break; case "D": constantValue = classFile.GetConstantPoolConstantDouble(index); break; case "Ljava.lang.String;": constantValue = classFile.GetConstantPoolConstantString(index); break; default: throw new ClassFormatError("{0} (Invalid signature for constant)", classFile.Name); } } catch(InvalidCastException) { throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); } catch(IndexOutOfRangeException) { throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); } catch(InvalidOperationException) { throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); } catch(NullReferenceException) { throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); } break; } case "Signature": if(classFile.MajorVersion < 49) { goto default; } if(br.ReadUInt32() != 2) { throw new ClassFormatError("Signature attribute has incorrect length"); } signature = classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); break; case "RuntimeVisibleAnnotations": if(classFile.MajorVersion < 49) { goto default; } annotations = ReadAnnotations(br, classFile, utf8_cp); break; case "RuntimeInvisibleAnnotations": if(classFile.MajorVersion < 49) { goto default; } foreach(object[] annot in ReadAnnotations(br, classFile, utf8_cp)) { if(annot[1].Equals("Likvm/lang/Property;")) { DecodePropertyAnnotation(classFile, annot); } #if STATIC_COMPILER else if(annot[1].Equals("Likvm/lang/Internal;")) { this.access_flags &= ~Modifiers.AccessMask; flags |= FLAG_MASK_INTERNAL; } #endif } break; default: br.Skip(br.ReadUInt32()); break; } } }
/// <summary> /// Default ctor /// </summary> internal JavaLangByteBuilder(ClassFile cf) : base(cf, "System.SByte", "java/lang/Byte") { }
internal Method(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options, BigEndianBinaryReader br) : base(classFile, utf8_cp, br) { // vmspec 4.6 says that all flags, except ACC_STRICT are ignored on <clinit> // however, since Java 7 it does need to be marked static if(ReferenceEquals(Name, StringConstants.CLINIT) && ReferenceEquals(Signature, StringConstants.SIG_VOID) && (classFile.MajorVersion < 51 || IsStatic)) { access_flags &= Modifiers.Strictfp; access_flags |= (Modifiers.Static | Modifiers.Private); } else { // LAMESPEC: vmspec 4.6 says that abstract methods can not be strictfp (and this makes sense), but // javac (pre 1.5) is broken and marks abstract methods as strictfp (if you put the strictfp on the class) if((ReferenceEquals(Name, StringConstants.INIT) && (IsStatic || IsSynchronized || IsFinal || IsAbstract || IsNative)) || (IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected) || (IsAbstract && (IsFinal || IsNative || IsPrivate || IsStatic || IsSynchronized)) || (classFile.IsInterface && (!IsPublic || !IsAbstract))) { throw new ClassFormatError("{0} (Illegal method modifiers: 0x{1:X})", classFile.Name, access_flags); } } int attributes_count = br.ReadUInt16(); for(int i = 0; i < attributes_count; i++) { switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) { case "Deprecated": if(br.ReadUInt32() != 0) { throw new ClassFormatError("Invalid Deprecated attribute length"); } flags |= FLAG_MASK_DEPRECATED; break; case "Code": { if(!code.IsEmpty) { throw new ClassFormatError("{0} (Duplicate Code attribute)", classFile.Name); } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); code.Read(classFile, utf8_cp, this, rdr, options); if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (Code attribute has wrong length)", classFile.Name); } break; } case "Exceptions": { if(exceptions != null) { throw new ClassFormatError("{0} (Duplicate Exceptions attribute)", classFile.Name); } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); ushort count = rdr.ReadUInt16(); exceptions = new string[count]; for(int j = 0; j < count; j++) { exceptions[j] = classFile.GetConstantPoolClass(rdr.ReadUInt16()); } if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (Exceptions attribute has wrong length)", classFile.Name); } break; } case "Signature": if(classFile.MajorVersion < 49) { goto default; } if(br.ReadUInt32() != 2) { throw new ClassFormatError("Signature attribute has incorrect length"); } signature = classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); break; case "RuntimeVisibleAnnotations": if(classFile.MajorVersion < 49) { goto default; } annotations = ReadAnnotations(br, classFile, utf8_cp); break; case "RuntimeVisibleParameterAnnotations": { if(classFile.MajorVersion < 49) { goto default; } if(low == null) { low = new LowFreqData(); } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); byte num_parameters = rdr.ReadByte(); low.parameterAnnotations = new object[num_parameters][]; for(int j = 0; j < num_parameters; j++) { ushort num_annotations = rdr.ReadUInt16(); low.parameterAnnotations[j] = new object[num_annotations]; for(int k = 0; k < num_annotations; k++) { low.parameterAnnotations[j][k] = ReadAnnotation(rdr, classFile, utf8_cp); } } if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (RuntimeVisibleParameterAnnotations attribute has wrong length)", classFile.Name); } break; } case "AnnotationDefault": { if(classFile.MajorVersion < 49) { goto default; } if(low == null) { low = new LowFreqData(); } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); low.annotationDefault = ReadAnnotationElementValue(rdr, classFile, utf8_cp); if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (AnnotationDefault attribute has wrong length)", classFile.Name); } break; } #if STATIC_COMPILER case "RuntimeInvisibleAnnotations": if(classFile.MajorVersion < 49) { goto default; } foreach(object[] annot in ReadAnnotations(br, classFile, utf8_cp)) { if(annot[1].Equals("Likvm/lang/Internal;")) { if (classFile.IsInterface) { StaticCompiler.IssueMessage(Message.InterfaceMethodCantBeInternal, classFile.Name, this.Name, this.Signature); } else { this.access_flags &= ~Modifiers.AccessMask; flags |= FLAG_MASK_INTERNAL; } } if(annot[1].Equals("Likvm/internal/HasCallerID;")) { flags |= FLAG_HAS_CALLERID; } if(annot[1].Equals("Likvm/lang/DllExport;")) { string name = null; int? ordinal = null; for (int j = 2; j < annot.Length; j += 2) { if (annot[j].Equals("name") && annot[j + 1] is string) { name = (string)annot[j + 1]; } else if (annot[j].Equals("ordinal") && annot[j + 1] is int) { ordinal = (int)annot[j + 1]; } } if (name != null && ordinal != null) { if (!IsStatic) { StaticCompiler.IssueMessage(Message.DllExportMustBeStaticMethod, classFile.Name, this.Name, this.Signature); } else { if (low == null) { low = new LowFreqData(); } low.DllExportName = name; low.DllExportOrdinal = ordinal.Value; } } } } break; #endif default: br.Skip(br.ReadUInt32()); break; } } if(IsAbstract || IsNative) { if(!code.IsEmpty) { throw new ClassFormatError("Abstract or native method cannot have a Code attribute"); } } else { if(code.IsEmpty) { if(ReferenceEquals(this.Name, StringConstants.CLINIT)) { code.verifyError = string.Format("Class {0}, method {1} signature {2}: No Code attribute", classFile.Name, this.Name, this.Signature); return; } throw new ClassFormatError("Method has no Code attribute"); } } }
internal static bool Emit(DynamicTypeWrapper.FinishContext context, TypeWrapper wrapper, CodeEmitter ilgen, ClassFile classFile, int i, ClassFile.Method.Instruction[] code, InstructionFlags[] flags) { if (i >= 3 && (flags[i - 0] & InstructionFlags.BranchTarget) == 0 && (flags[i - 1] & InstructionFlags.BranchTarget) == 0 && (flags[i - 2] & InstructionFlags.BranchTarget) == 0 && (flags[i - 3] & InstructionFlags.BranchTarget) == 0 && code[i - 1].NormalizedOpCode == NormalizedByteCode.__ldc && code[i - 2].NormalizedOpCode == NormalizedByteCode.__ldc && code[i - 3].NormalizedOpCode == NormalizedByteCode.__ldc) { // we now have a structural match, now we need to make sure that the argument values are what we expect TypeWrapper tclass = classFile.GetConstantPoolClassType(code[i - 3].Arg1); TypeWrapper vclass = classFile.GetConstantPoolClassType(code[i - 2].Arg1); string fieldName = classFile.GetConstantPoolConstantString(code[i - 1].Arg1); if (tclass == wrapper && !vclass.IsUnloadable && !vclass.IsPrimitive && !vclass.IsNonPrimitiveValueType) { FieldWrapper field = wrapper.GetFieldWrapper(fieldName, vclass.SigName); if (field != null && !field.IsStatic && field.IsVolatile && field.DeclaringType == wrapper && field.FieldTypeWrapper == vclass) { // everything matches up, now call the actual emitter DoEmit(context, wrapper, ilgen, field); return(true); } } } return(false); }
internal void Read(ClassFile classFile, string[] utf8_cp, Method method, BigEndianBinaryReader br, ClassFileParseOptions options) { max_stack = br.ReadUInt16(); max_locals = br.ReadUInt16(); uint code_length = br.ReadUInt32(); if(code_length > 65535) { throw new ClassFormatError("{0} (Invalid Code length {1})", classFile.Name, code_length); } Instruction[] instructions = new Instruction[code_length + 1]; int basePosition = br.Position; int instructionIndex = 0; try { BigEndianBinaryReader rdr = br.Section(code_length); while(!rdr.IsAtEnd) { instructions[instructionIndex].Read((ushort)(rdr.Position - basePosition), rdr, classFile); hasJsr |= instructions[instructionIndex].NormalizedOpCode == NormalizedByteCode.__jsr; instructionIndex++; } // we add an additional nop instruction to make it easier for consumers of the code array instructions[instructionIndex++].SetTermNop((ushort)(rdr.Position - basePosition)); } catch(ClassFormatError x) { // any class format errors in the code block are actually verify errors verifyError = x.Message; } this.instructions = new Instruction[instructionIndex]; Array.Copy(instructions, 0, this.instructions, 0, instructionIndex); // build the pcIndexMap int[] pcIndexMap = new int[this.instructions[instructionIndex - 1].PC + 1]; for(int i = 0; i < pcIndexMap.Length; i++) { pcIndexMap[i] = -1; } for(int i = 0; i < instructionIndex - 1; i++) { pcIndexMap[this.instructions[i].PC] = i; } // convert branch offsets to indexes for(int i = 0; i < instructionIndex - 1; i++) { switch(this.instructions[i].NormalizedOpCode) { case NormalizedByteCode.__ifeq: case NormalizedByteCode.__ifne: case NormalizedByteCode.__iflt: case NormalizedByteCode.__ifge: case NormalizedByteCode.__ifgt: case NormalizedByteCode.__ifle: case NormalizedByteCode.__if_icmpeq: case NormalizedByteCode.__if_icmpne: case NormalizedByteCode.__if_icmplt: case NormalizedByteCode.__if_icmpge: case NormalizedByteCode.__if_icmpgt: case NormalizedByteCode.__if_icmple: case NormalizedByteCode.__if_acmpeq: case NormalizedByteCode.__if_acmpne: case NormalizedByteCode.__ifnull: case NormalizedByteCode.__ifnonnull: case NormalizedByteCode.__goto: case NormalizedByteCode.__jsr: this.instructions[i].SetTargetIndex(pcIndexMap[this.instructions[i].Arg1 + this.instructions[i].PC]); break; case NormalizedByteCode.__tableswitch: case NormalizedByteCode.__lookupswitch: this.instructions[i].MapSwitchTargets(pcIndexMap); break; } } // read exception table ushort exception_table_length = br.ReadUInt16(); exception_table = new ExceptionTableEntry[exception_table_length]; for(int i = 0; i < exception_table_length; i++) { ushort start_pc = br.ReadUInt16(); ushort end_pc = br.ReadUInt16(); ushort handler_pc = br.ReadUInt16(); ushort catch_type = br.ReadUInt16(); if(start_pc >= end_pc || end_pc > code_length || handler_pc >= code_length || (catch_type != 0 && !classFile.SafeIsConstantPoolClass(catch_type))) { throw new ClassFormatError("Illegal exception table: {0}.{1}{2}", classFile.Name, method.Name, method.Signature); } classFile.MarkLinkRequiredConstantPoolItem(catch_type); // if start_pc, end_pc or handler_pc is invalid (i.e. doesn't point to the start of an instruction), // the index will be -1 and this will be handled by the verifier int startIndex = pcIndexMap[start_pc]; int endIndex; if (end_pc == code_length) { // it is legal for end_pc to point to just after the last instruction, // but since there isn't an entry in our pcIndexMap for that, we have // a special case for this endIndex = instructionIndex - 1; } else { endIndex = pcIndexMap[end_pc]; } int handlerIndex = pcIndexMap[handler_pc]; exception_table[i] = new ExceptionTableEntry(startIndex, endIndex, handlerIndex, catch_type, i); } ushort attributes_count = br.ReadUInt16(); for(int i = 0; i < attributes_count; i++) { switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) { case "LineNumberTable": if((options & ClassFileParseOptions.LineNumberTable) != 0) { BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); int count = rdr.ReadUInt16(); lineNumberTable = new LineNumberTableEntry[count]; for(int j = 0; j < count; j++) { lineNumberTable[j].start_pc = rdr.ReadUInt16(); lineNumberTable[j].line_number = rdr.ReadUInt16(); if(lineNumberTable[j].start_pc >= code_length) { throw new ClassFormatError("{0} (LineNumberTable has invalid pc)", classFile.Name); } } if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (LineNumberTable attribute has wrong length)", classFile.Name); } } else { br.Skip(br.ReadUInt32()); } break; case "LocalVariableTable": if((options & ClassFileParseOptions.LocalVariableTable) != 0) { BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); int count = rdr.ReadUInt16(); localVariableTable = new LocalVariableTableEntry[count]; for(int j = 0; j < count; j++) { localVariableTable[j].start_pc = rdr.ReadUInt16(); localVariableTable[j].length = rdr.ReadUInt16(); localVariableTable[j].name = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); localVariableTable[j].descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()).Replace('/', '.'); localVariableTable[j].index = rdr.ReadUInt16(); } // NOTE we're intentionally not checking that we're at the end of the section // (optional attributes shouldn't cause ClassFormatError) } else { br.Skip(br.ReadUInt32()); } break; default: br.Skip(br.ReadUInt32()); break; } } // build the argmap string sig = method.Signature; List<int> args = new List<int>(); int pos = 0; if(!method.IsStatic) { args.Add(pos++); } for(int i = 1; sig[i] != ')'; i++) { args.Add(pos++); switch(sig[i]) { case 'L': i = sig.IndexOf(';', i); break; case 'D': case 'J': args.Add(-1); break; case '[': { while(sig[i] == '[') { i++; } if(sig[i] == 'L') { i = sig.IndexOf(';', i); } break; } } } argmap = args.ToArray(); if(args.Count > max_locals) { throw new ClassFormatError("{0} (Arguments can't fit into locals)", classFile.Name); } }
/// <summary> /// Default ctor /// </summary> internal JavaLangThreadBuilder(ClassFile cf) : base(cf, "System.Threading.Thread", "java/lang/Thread") { }
/// <summary> /// Gets all classes that the given classes extends or implements /// </summary> private IEnumerable<ClassFile> SelfBaseAndImplementedClasses(ClassFile original) { // Return self yield return original; // Base classes var currentClass = original; while (currentClass != null) { if (currentClass.TryGetSuperClass(out currentClass)) { yield return currentClass; } else { break; } } // Implemented interfaces currentClass = original; while (currentClass != null) { if (currentClass.Interfaces != null) { foreach (var intfRef in currentClass.Interfaces) { ClassFile intfClass; if (Loader.TryLoadClass(intfRef.ClassName, out intfClass)) { foreach (var x in SelfBaseAndImplementedClasses(intfClass)) { yield return x; } } } } if (currentClass.TryGetSuperClass(out currentClass)) { yield return currentClass; } else { break; } } }
internal sealed override TypeWrapper DefineClassImpl(Dictionary <string, TypeWrapper> types, TypeWrapper host, ClassFile f, ClassLoaderWrapper classLoader, ProtectionDomain protectionDomain) { #if STATIC_COMPILER AotTypeWrapper type = new AotTypeWrapper(f, (CompilerClassLoader)classLoader); type.CreateStep1(); types[f.Name] = type; return(type); #elif FIRST_PASS return(null); #else // this step can throw a retargettable exception, if the class is incorrect DynamicTypeWrapper type = new DynamicTypeWrapper(host, f, classLoader, protectionDomain); // This step actually creates the TypeBuilder. It is not allowed to throw any exceptions, // if an exception does occur, it is due to a programming error in the IKVM or CLR runtime // and will cause a CriticalFailure and exit the process. type.CreateStep1(); type.CreateStep2(); if (types == null) { // we're defining an anonymous class, so we don't need any locking TieClassAndWrapper(type, protectionDomain); return(type); } lock (types) { // in very extreme conditions another thread may have beaten us to it // and loaded (not defined) a class with the same name, in that case // we'll leak the the Reflection.Emit defined type. Also see the comment // in ClassLoaderWrapper.RegisterInitiatingLoader(). TypeWrapper race; types.TryGetValue(f.Name, out race); if (race == null) { types[f.Name] = type; TieClassAndWrapper(type, protectionDomain); } else { throw new LinkageError("duplicate class definition: " + f.Name); } } return(type); #endif // STATIC_COMPILER }