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 Method(ClassFile classFile, BigEndianBinaryReader br) : base(classFile, br) { // vmspec 4.6 says that all flags, except ACC_STRICT are ignored on <clinit> if (Name == "<clinit>" && Signature == "()V") { 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 ((Name == "<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(br.ReadUInt16())) { case "Deprecated": deprecated = true; #if FUZZ_HACK br.Skip(br.ReadUInt32()); #else if(br.ReadUInt32() != 0) { throw new ClassFormatError("{0} (Deprecated attribute has non-zero length)", classFile.Name); } #endif break; case "Code": { if (!code.IsEmpty) { throw new ClassFormatError("{0} (Duplicate Code attribute)", classFile.Name); } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); code.Read(classFile, this, rdr); 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; } 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 FUZZ_HACK if (this.Name == "<clinit>") { code.verifyError = string.Format("Class {0}, method {1} signature {2}: No Code attribute", classFile.Name, this.Name, this.Signature); return; } #endif throw new ClassFormatError("Method has no Code attribute"); } } }