Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/tools/java/BinaryClass.java
38918 views
/*1* Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.tools.java;2627import java.io.IOException;28import java.io.DataInputStream;29import java.io.OutputStream;30import java.io.DataOutputStream;31import java.io.ByteArrayInputStream;32import java.util.Hashtable;33import java.util.Vector;34import java.util.Enumeration;3536/**37* WARNING: The contents of this source file are not part of any38* supported API. Code that depends on them does so at its own risk:39* they are subject to change or removal without notice.40*/41public final42class BinaryClass extends ClassDefinition implements Constants {43BinaryConstantPool cpool;44BinaryAttribute atts;45Vector dependencies;46private boolean haveLoadedNested = false;4748/**49* Constructor50*/51public BinaryClass(Object source, ClassDeclaration declaration, int modifiers,52ClassDeclaration superClass, ClassDeclaration interfaces[],53Vector dependencies) {54super(source, 0, declaration, modifiers, null, null);55this.dependencies = dependencies;56this.superClass = superClass;57this.interfaces = interfaces;58}5960/**61* Flags used by basicCheck() to avoid duplicate calls.62* (Part of fix for 4105911)63*/64private boolean basicCheckDone = false;65private boolean basicChecking = false;6667/**68* Ready a BinaryClass for further checking. Note that, until recently,69* BinaryClass relied on the default basicCheck() provided by70* ClassDefinition. The definition here has been added to ensure that71* the information generated by collectInheritedMethods is available72* for BinaryClasses.73*/74protected void basicCheck(Environment env) throws ClassNotFound {75if (tracing) env.dtEnter("BinaryClass.basicCheck: " + getName());7677// We need to guard against duplicate calls to basicCheck(). They78// can lead to calling collectInheritedMethods() for this class79// from within a previous call to collectInheritedMethods() for80// this class. That is not allowed.81// (Part of fix for 4105911)82if (basicChecking || basicCheckDone) {83if (tracing) env.dtExit("BinaryClass.basicCheck: OK " + getName());84return;85}8687if (tracing) env.dtEvent("BinaryClass.basicCheck: CHECKING " + getName());88basicChecking = true;8990super.basicCheck(env);9192// Collect inheritance information.93if (doInheritanceChecks) {94collectInheritedMethods(env);95}9697basicCheckDone = true;98basicChecking = false;99if (tracing) env.dtExit("BinaryClass.basicCheck: " + getName());100}101102/**103* Load a binary class104*/105public static BinaryClass load(Environment env, DataInputStream in) throws IOException {106return load(env, in, ~(ATT_CODE|ATT_ALLCLASSES));107}108109public static BinaryClass load(Environment env,110DataInputStream in, int mask) throws IOException {111// Read the header112int magic = in.readInt(); // JVM 4.1 ClassFile.magic113if (magic != JAVA_MAGIC) {114throw new ClassFormatError("wrong magic: " + magic + ", expected " + JAVA_MAGIC);115}116int minor_version = in.readUnsignedShort(); // JVM 4.1 ClassFile.minor_version117int version = in.readUnsignedShort(); // JVM 4.1 ClassFile.major_version118if (version < JAVA_MIN_SUPPORTED_VERSION) {119throw new ClassFormatError(120sun.tools.javac.Main.getText(121"javac.err.version.too.old",122String.valueOf(version)));123} else if ((version > JAVA_MAX_SUPPORTED_VERSION)124|| (version == JAVA_MAX_SUPPORTED_VERSION125&& minor_version > JAVA_MAX_SUPPORTED_MINOR_VERSION)) {126throw new ClassFormatError(127sun.tools.javac.Main.getText(128"javac.err.version.too.recent",129version+"."+minor_version));130}131132// Read the constant pool133BinaryConstantPool cpool = new BinaryConstantPool(in);134135// The dependencies of this class136Vector dependencies = cpool.getDependencies(env);137138// Read modifiers139int classMod = in.readUnsignedShort() & ACCM_CLASS; // JVM 4.1 ClassFile.access_flags140141// Read the class name - from JVM 4.1 ClassFile.this_class142ClassDeclaration classDecl = cpool.getDeclaration(env, in.readUnsignedShort());143144// Read the super class name (may be null) - from JVM 4.1 ClassFile.super_class145ClassDeclaration superClassDecl = cpool.getDeclaration(env, in.readUnsignedShort());146147// Read the interface names - from JVM 4.1 ClassFile.interfaces_count148ClassDeclaration interfaces[] = new ClassDeclaration[in.readUnsignedShort()];149for (int i = 0 ; i < interfaces.length ; i++) {150// JVM 4.1 ClassFile.interfaces[]151interfaces[i] = cpool.getDeclaration(env, in.readUnsignedShort());152}153154// Allocate the class155BinaryClass c = new BinaryClass(null, classDecl, classMod, superClassDecl,156interfaces, dependencies);157c.cpool = cpool;158159// Add any additional dependencies160c.addDependency(superClassDecl);161162// Read the fields163int nfields = in.readUnsignedShort(); // JVM 4.1 ClassFile.fields_count164for (int i = 0 ; i < nfields ; i++) {165// JVM 4.5 field_info.access_flags166int fieldMod = in.readUnsignedShort() & ACCM_FIELD;167// JVM 4.5 field_info.name_index168Identifier fieldName = cpool.getIdentifier(in.readUnsignedShort());169// JVM 4.5 field_info.descriptor_index170Type fieldType = cpool.getType(in.readUnsignedShort());171BinaryAttribute atts = BinaryAttribute.load(in, cpool, mask);172c.addMember(new BinaryMember(c, fieldMod, fieldType, fieldName, atts));173}174175// Read the methods176int nmethods = in.readUnsignedShort(); // JVM 4.1 ClassFile.methods_count177for (int i = 0 ; i < nmethods ; i++) {178// JVM 4.6 method_info.access_flags179int methMod = in.readUnsignedShort() & ACCM_METHOD;180// JVM 4.6 method_info.name_index181Identifier methName = cpool.getIdentifier(in.readUnsignedShort());182// JVM 4.6 method_info.descriptor_index183Type methType = cpool.getType(in.readUnsignedShort());184BinaryAttribute atts = BinaryAttribute.load(in, cpool, mask);185c.addMember(new BinaryMember(c, methMod, methType, methName, atts));186}187188// Read the class attributes189c.atts = BinaryAttribute.load(in, cpool, mask);190191// See if the SourceFile is known192byte data[] = c.getAttribute(idSourceFile);193if (data != null) {194DataInputStream dataStream = new DataInputStream(new ByteArrayInputStream(data));195// JVM 4.7.2 SourceFile_attribute.sourcefile_index196c.source = cpool.getString(dataStream.readUnsignedShort());197}198199// See if the Documentation is know200data = c.getAttribute(idDocumentation);201if (data != null) {202c.documentation = new DataInputStream(new ByteArrayInputStream(data)).readUTF();203}204205// Was it compiled as deprecated?206if (c.getAttribute(idDeprecated) != null) {207c.modifiers |= M_DEPRECATED;208}209210// Was it synthesized by the compiler?211if (c.getAttribute(idSynthetic) != null) {212c.modifiers |= M_SYNTHETIC;213}214215return c;216}217218/**219* Called when an environment ties a binary definition to a declaration.220* At this point, auxiliary definitions may be loaded.221*/222223public void loadNested(Environment env) {224loadNested(env, 0);225}226227public void loadNested(Environment env, int flags) {228// Sanity check.229if (haveLoadedNested) {230// Duplicate calls most likely should not occur, but they do231// in javap. Be tolerant of them for the time being.232// throw new CompilerError("multiple loadNested");233if (tracing) env.dtEvent("loadNested: DUPLICATE CALL SKIPPED");234return;235}236haveLoadedNested = true;237// Read class-nesting information.238try {239byte data[];240data = getAttribute(idInnerClasses);241if (data != null) {242initInnerClasses(env, data, flags);243}244} catch (IOException ee) {245// The inner classes attribute is not well-formed.246// It may, for example, contain no data. Report this.247// We used to throw a CompilerError here (bug 4095108).248env.error(0, "malformed.attribute", getClassDeclaration(),249idInnerClasses);250if (tracing)251env.dtEvent("loadNested: MALFORMED ATTRIBUTE (InnerClasses)");252}253}254255private void initInnerClasses(Environment env,256byte data[],257int flags) throws IOException {258DataInputStream ds = new DataInputStream(new ByteArrayInputStream(data));259int nrec = ds.readUnsignedShort(); // InnerClasses_attribute.number_of_classes260for (int i = 0; i < nrec; i++) {261// For each inner class name transformation, we have a record262// with the following fields:263//264// u2 inner_class_info_index; // CONSTANT_Class_info index265// u2 outer_class_info_index; // CONSTANT_Class_info index266// u2 inner_name_index; // CONSTANT_Utf8_info index267// u2 inner_class_access_flags; // access_flags bitmask268//269// The spec states that outer_class_info_index is 0 iff270// the inner class is not a member of its enclosing class (i.e.271// it is a local or anonymous class). The spec also states272// that if a class is anonymous then inner_name_index should273// be 0.274//275// Prior to jdk1.2, javac did not implement the spec. Instead276// it <em>always</em> set outer_class_info_index to the277// enclosing outer class and if the class was anonymous,278// it set inner_name_index to be the index of a CONSTANT_Utf8279// entry containing the null string "" (idNull). This code is280// designed to handle either kind of class file.281//282// See also the compileClass() method in SourceClass.java.283284// Read in the inner_class_info285// InnerClasses_attribute.classes.inner_class_info_index286int inner_index = ds.readUnsignedShort();287// could check for zero.288ClassDeclaration inner = cpool.getDeclaration(env, inner_index);289290// Read in the outer_class_info. Note that the index will be291// zero if the class is "not a member".292ClassDeclaration outer = null;293// InnerClasses_attribute.classes.outer_class_info_index294int outer_index = ds.readUnsignedShort();295if (outer_index != 0) {296outer = cpool.getDeclaration(env, outer_index);297}298299// Read in the inner_name_index. This may be zero. An anonymous300// class will either have an inner_nm_index of zero (as the spec301// dictates) or it will have an inner_nm of idNull (for classes302// generated by pre-1.2 compilers). Handle both.303Identifier inner_nm = idNull;304// InnerClasses_attribute.classes.inner_name_index305int inner_nm_index = ds.readUnsignedShort();306if (inner_nm_index != 0) {307inner_nm = Identifier.lookup(cpool.getString(inner_nm_index));308}309310// Read in the modifiers for the inner class.311// InnerClasses_attribute.classes.inner_name_index312int mods = ds.readUnsignedShort();313314// Is the class accessible?315// The old code checked for316//317// (!inner_nm.equals(idNull) && (mods & M_PRIVATE) == 0)318//319// which we will preserve to keep it working for class files320// generated by 1.1 compilers. In addition we check for321//322// (outer != null)323//324// as an additional check that only makes sense with 1.2325// generated files. Note that it is entirely possible that326// the M_PRIVATE bit is always enough. We are being327// conservative here.328//329// The ATT_ALLCLASSES flag causes the M_PRIVATE modifier330// to be ignored, and is used by tools such as 'javap' that331// wish to examine all classes regardless of the normal access332// controls that apply during compilation. Note that anonymous333// and local classes are still not considered accessible, though334// named local classes in jdk1.1 may slip through. Note that335// this accessibility test is an optimization, and it is safe to336// err on the side of greater accessibility.337boolean accessible =338(outer != null) &&339(!inner_nm.equals(idNull)) &&340((mods & M_PRIVATE) == 0 ||341(flags & ATT_ALLCLASSES) != 0);342343// The reader should note that there has been a significant change344// in the way that the InnerClasses attribute is being handled.345// In particular, previously the compiler called initInner() for346// <em>every</em> inner class. Now the compiler does not call347// initInner() if the inner class is inaccessible. This means348// that inaccessible inner classes don't have any of the processing349// from initInner() done for them: fixing the access flags,350// setting outerClass, setting outerMember in their outerClass,351// etc. We believe this is fine: if the class is inaccessible352// and binary, then everyone who needs to see its internals353// has already been compiled. Hopefully.354355if (accessible) {356Identifier nm =357Identifier.lookupInner(outer.getName(), inner_nm);358359// Tell the type module about the nesting relation:360Type.tClass(nm);361362if (inner.equals(getClassDeclaration())) {363// The inner class in the record is this class.364try {365ClassDefinition outerClass = outer.getClassDefinition(env);366initInner(outerClass, mods);367} catch (ClassNotFound e) {368// report the error elsewhere369}370} else if (outer.equals(getClassDeclaration())) {371// The outer class in the record is this class.372try {373ClassDefinition innerClass =374inner.getClassDefinition(env);375initOuter(innerClass, mods);376} catch (ClassNotFound e) {377// report the error elsewhere378}379}380}381}382}383384private void initInner(ClassDefinition outerClass, int mods) {385if (getOuterClass() != null)386return; // already done387/******388// Maybe set static, protected, or private.389if ((modifiers & M_PUBLIC) != 0)390mods &= M_STATIC;391else392mods &= M_PRIVATE | M_PROTECTED | M_STATIC;393modifiers |= mods;394******/395// For an inner class, the class access may have been weakened396// from that originally declared the source. We must take the397// actual access permissions against which we check any source398// we are currently compiling from the InnerClasses attribute.399// We attempt to guard here against bogus combinations of modifiers.400if ((mods & M_PRIVATE) != 0) {401// Private cannot be combined with public or protected.402mods &= ~(M_PUBLIC | M_PROTECTED);403} else if ((mods & M_PROTECTED) != 0) {404// Protected cannot be combined with public.405mods &= ~M_PUBLIC;406}407if ((mods & M_INTERFACE) != 0) {408// All interfaces are implicitly abstract.409// All interfaces that are members of a type are implicitly static.410mods |= (M_ABSTRACT | M_STATIC);411}412if (outerClass.isInterface()) {413// All types that are members of interfaces are implicitly414// public and static.415mods |= (M_PUBLIC | M_STATIC);416mods &= ~(M_PRIVATE | M_PROTECTED);417}418modifiers = mods;419420setOuterClass(outerClass);421422for (MemberDefinition field = getFirstMember();423field != null;424field = field.getNextMember()) {425if (field.isUplevelValue()426&& outerClass.getType().equals(field.getType())427&& field.getName().toString().startsWith(prefixThis)) {428setOuterMember(field);429}430}431}432433private void initOuter(ClassDefinition innerClass, int mods) {434if (innerClass instanceof BinaryClass)435((BinaryClass)innerClass).initInner(this, mods);436addMember(new BinaryMember(innerClass));437}438439/**440* Write the class out to a given stream. This function mirrors the loader.441*/442public void write(Environment env, OutputStream out) throws IOException {443DataOutputStream data = new DataOutputStream(out);444445// write out the header446data.writeInt(JAVA_MAGIC);447data.writeShort(env.getMinorVersion());448data.writeShort(env.getMajorVersion());449450// Write out the constant pool451cpool.write(data, env);452453// Write class information454data.writeShort(getModifiers() & ACCM_CLASS);455data.writeShort(cpool.indexObject(getClassDeclaration(), env));456data.writeShort((getSuperClass() != null)457? cpool.indexObject(getSuperClass(), env) : 0);458data.writeShort(interfaces.length);459for (int i = 0 ; i < interfaces.length ; i++) {460data.writeShort(cpool.indexObject(interfaces[i], env));461}462463// count the fields and the methods464int fieldCount = 0, methodCount = 0;465for (MemberDefinition f = firstMember; f != null; f = f.getNextMember())466if (f.isMethod()) methodCount++; else fieldCount++;467468// write out each the field count, and then each field469data.writeShort(fieldCount);470for (MemberDefinition f = firstMember; f != null; f = f.getNextMember()) {471if (!f.isMethod()) {472data.writeShort(f.getModifiers() & ACCM_FIELD);473String name = f.getName().toString();474String signature = f.getType().getTypeSignature();475data.writeShort(cpool.indexString(name, env));476data.writeShort(cpool.indexString(signature, env));477BinaryAttribute.write(((BinaryMember)f).atts, data, cpool, env);478}479}480481// write out each method count, and then each method482data.writeShort(methodCount);483for (MemberDefinition f = firstMember; f != null; f = f.getNextMember()) {484if (f.isMethod()) {485data.writeShort(f.getModifiers() & ACCM_METHOD);486String name = f.getName().toString();487String signature = f.getType().getTypeSignature();488data.writeShort(cpool.indexString(name, env));489data.writeShort(cpool.indexString(signature, env));490BinaryAttribute.write(((BinaryMember)f).atts, data, cpool, env);491}492}493494// write out the class attributes495BinaryAttribute.write(atts, data, cpool, env);496data.flush();497}498499/**500* Get the dependencies501*/502public Enumeration getDependencies() {503return dependencies.elements();504}505506/**507* Add a dependency508*/509public void addDependency(ClassDeclaration c) {510if ((c != null) && !dependencies.contains(c)) {511dependencies.addElement(c);512}513}514515/**516* Get the constant pool517*/518public BinaryConstantPool getConstants() {519return cpool;520}521522/**523* Get a class attribute524*/525public byte getAttribute(Identifier name)[] {526for (BinaryAttribute att = atts ; att != null ; att = att.next) {527if (att.name.equals(name)) {528return att.data;529}530}531return null;532}533}534535536