summaryrefslogblamecommitdiff
path: root/sources/scalac/symtab/classfile/ClassfileParser.java
blob: 073df39e90ab57793578d18e126d5f54926be641 (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                                                          
                                     
                                 


                       
                                          











                                                            
                                             

                                            



                                                  


                                               


                                                      

                                            
 


                                          
                             








                                                                                                                      


                             
                                  
                                       

                         
                                                          

                                   





                                                                 

                                                                                             
             




                                                                              




                                                        




                                                                     


                                                                           
                                      

                                                        
                                                                     









                                                                            

                                            
                                                    
                                                                             

                                                          



                                                                    
                                                  


                                                                                          
                                                    








                                                           
 

                                                   
                               



                                                                
                                                            

                                                                   

                                                                        
 














                                                                     
                                               
                           



                                                                          
                                          


















                                                                         


         

                                                
                                                
                                             
         







                                                     



                                               
                                            
                                     
                                                   
                                       


                                                
                                      
                                          
                                   
                                              
                                                                              

                                              


                                    


                                                                 
                                                                          




                                 














                                                                        




                                  

                                        
                                                                         










                                                          



                                                           








                                                                          
                    
                                                                     
             


                                                           




                                                             
         
     
 


                                                          
                                                                     







                                                                  

                                                          









                                                                                                  
     
 
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
**                                                                      **
** $Id$
\*                                                                      */

package scalac.symtab.classfile;

import scala.tools.util.AbstractFile;
import scala.tools.util.Position;
import scalac.*;
import scalac.util.*;
import scalac.symtab.*;
import scalac.symtab.Scope.SymbolIterator;
import java.io.*;
import java.util.*;

//todo: don't keep statics module in scope.

public class ClassfileParser implements ClassfileConstants {

    static final int CLASS_ATTR  = SOURCEFILE_ATTR
                                 | INNERCLASSES_ATTR
                                 | SYNTHETIC_ATTR
                                 | DEPRECATED_ATTR
                                 | META_ATTR
                                 | SCALA_ATTR
                                 | JACO_ATTR
                                 | SIG_ATTR;
    static final int METH_ATTR   = CODE_ATTR
                                 | EXCEPTIONS_ATTR
                                 | SYNTHETIC_ATTR
                                 | DEPRECATED_ATTR
                                 | META_ATTR
                                 | SIG_ATTR
                                 | BRIDGE_ATTR;
    static final int FIELD_ATTR  = CONSTANT_VALUE_ATTR
                                 | SYNTHETIC_ATTR
                                 | DEPRECATED_ATTR
                                 | META_ATTR
                                 | SIG_ATTR;

    protected final Global global;
    protected final AbstractFileReader in;
    protected final Symbol c;
    protected final Symbol m;
    protected final Type ctype;
    protected final JavaTypeFactory make;
    protected final ConstantPool pool;
    protected final AttributeParser attrib;
    protected final Scope locals;
    protected final Scope statics;


    private ClassfileParser(Global global, AbstractFileReader in, Symbol c, JavaTypeFactory make, ConstantPool pool) {
        this.global = global;
        this.in = in;
        this.c = c;
        this.m = c.linkedModule();
        this.ctype = make.classType(c);
        this.make = make;
        this.pool = pool;
        this.attrib = new AttributeParser(in, pool, this);
        this.locals = new Scope();
        this.statics = new Scope();
    }


    /** parse the classfile and throw IO exception if there is an
     *  error in the classfile structure
     */
    public static void parse(Global global, AbstractFile file, Symbol c) throws IOException {
        AbstractFileReader in = new AbstractFileReader(file);
        try {
            int magic = in.nextInt();
            if (magic != JAVA_MAGIC)
                throw new IOException("class file '" + in.path + "' "
                    + "has wrong magic number 0x" + Integer.toHexString(magic)
                    + ", should be 0x" + Integer.toHexString(JAVA_MAGIC));
            int minorVersion = in.nextChar();
            int majorVersion = in.nextChar();
            if ((majorVersion < JAVA_MAJOR_VERSION) ||
                ((majorVersion == JAVA_MAJOR_VERSION) &&
                 (minorVersion < JAVA_MINOR_VERSION)))
                throw new IOException("class file '" + in.path + "' "
                    + "has unknown version "
                    + majorVersion + "." + minorVersion
                    + ", should be less than "
                    + JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION);
            JavaTypeFactory make = new JavaTypeCreator(global.definitions);
            Signatures sigs = new Signatures(global, make, in);
            ConstantPool pool = new ConstantPool(in, sigs);
            int flags = in.nextChar();
            Symbol clasz = pool.getClass(in.nextChar());
            if (c != clasz)
                throw new IOException("class file '" + in.path + "' "
                    + "contains wrong class " + clasz.staticType());
            new ClassfileParser(global, in, c, make, pool).parse(flags);
        } catch (RuntimeException e) {
            if (global.debug) e.printStackTrace();
            throw new IOException("class file '" + in.path + "' is broken");
        }
    }

    protected void parse(int flags) {
        {
            // todo: correct flag transition
            c.flags = transFlags(flags);
            if ((c.flags & Modifiers.DEFERRED) != 0)
                c.flags = c.flags & ~Modifiers.DEFERRED | Modifiers.ABSTRACT;
            Type supertpe = readClassType(in.nextChar());
            Type[] basetpes = new Type[in.nextChar() + 1];
            // set info of class
            Type classInfo = Type.compoundType(basetpes, locals, c);
            c.setInfo(classInfo);
            // set info of statics class
            Symbol staticsClass = m.moduleClass();
            assert staticsClass.isModuleClass(): Debug.show(staticsClass);
            Type staticsInfo = Type.compoundType(Type.EMPTY_ARRAY, statics, staticsClass);
            staticsClass.setInfo(staticsInfo);
            m.setInfo(make.classType(staticsClass));
            basetpes[0] = supertpe;
            for (int i = 1; i < basetpes.length; i++)
                basetpes[i] = readClassType(in.nextChar());
            int fieldCount = in.nextChar();
            for (int i = 0; i < fieldCount; i++)
                parseField();
            int methodCount = in.nextChar();
            for (int i = 0; i < methodCount; i++)
                parseMethod();

            Symbol constr = c.primaryConstructor();
            if (!constr.isInitialized()) {
                constr.setInfo(
                    Type.MethodType(Symbol.EMPTY_ARRAY, ctype));
                if ((c.flags & Modifiers.INTERFACE) == 0)
                    constr.flags |= Modifiers.PRIVATE;
            }
            attrib.readAttributes(c, classInfo, CLASS_ATTR);
            //System.out.println("dynamic class: " + c);
            //System.out.println("statics class: " + staticsClass);
            //System.out.println("module: " + m);
            //System.out.println("modules class: " + m.type().symbol());

            int savedFlags = c.flags;
            c.flags |= Modifiers.INITIALIZED;
            // hack to make memberType in addInheritedOverloaded work
	    addInheritedOverloaded();

            //if (global.debug) {
            //    Symbol[] elems = c.members().elements();
            //    global.log(c + " defines: ");
            //    for (int i = 0; i < elems.length; i++) {
            //        global.log(elems[i] + ":" + elems[i].type());
            //    }
            //}

            c.flags = savedFlags;

            // Add static members of superclass
	    // todo: remove
            Symbol superclass = supertpe.symbol();
            if (m.isJava() && superclass.isJava()) {
                Symbol mclass = m.moduleClass();
                SymbolIterator i = superclass.linkedModule().moduleClass()
                    .members().iterator();
                outer:
                while (i.hasNext()) {
                    Symbol member = i.next();
                    Symbol current = statics.lookup(member.name);
                    if (!current.isNone()) {
                        if (!member.isTerm()) continue outer;
                        Type info = member.info();
                        Symbol[] currents = current.alternativeSymbols();
                        inner:
                        for (int j = 0; j < currents.length; j++) {
                            if (currents[j].owner() != mclass)
                                continue inner;
                            if (currents[j].info().isSubType(info))
                                continue outer;
                        }
                    }
                    statics.enterOrOverload(member);
                }
            }
        }
    }

    private void addInheritedOverloaded() {
        Symbol[] elems = c.members().elements();
        for (int i = 0; i < elems.length; i++) {
            addInheritedOverloaded(elems[i]);
        }
    }

    private void addInheritedOverloaded(Symbol sym) {
	if (sym.isMethod() && !sym.isConstructor()) {
            sym.addInheritedOverloaded(sym.type());
        }
    }

    /** convert Java modifiers into Scala flags
     */
    public int transFlags(int flags) {
        int res = 0;
        if ((flags & JAVA_ACC_PRIVATE) != 0)
            res |= Modifiers.PRIVATE;
        else if ((flags & JAVA_ACC_PROTECTED) != 0)
            res |= Modifiers.PROTECTED;
        else if ((flags & JAVA_ACC_PUBLIC) == 0)
            res |= Modifiers.PRIVATE;
        if ((flags & JAVA_ACC_ABSTRACT) != 0)
            res |= Modifiers.DEFERRED;
        if ((flags & JAVA_ACC_FINAL) != 0)
            res |= Modifiers.FINAL;
        if ((flags & JAVA_ACC_INTERFACE) != 0)
            res |= Modifiers.INTERFACE | Modifiers.TRAIT | Modifiers.ABSTRACT;
        if ((flags & JAVA_ACC_SYNTHETIC) != 0)
            res |= Modifiers.SYNTHETIC;
        return res | Modifiers.JAVA;
    }

    /** read a class name and return the corresponding class type
     */
    protected Type readClassType(int i) {
        return i == 0 ? make.anyType() : make.classType(pool.getClass(i));
    }

    /** read a field
     */
    protected void parseField() {
        int jflags = in.nextChar();
        int sflags = transFlags(jflags);
        if ((jflags & JAVA_ACC_FINAL) == 0) sflags |= Modifiers.MUTABLE;
        if ((sflags & Modifiers.PRIVATE) != 0) {
            in.skip(4);
            attrib.skipAttributes();
        } else {
            Name name = pool.getName(in.nextChar());
            Symbol owner = getOwner(jflags);
            Symbol symbol = owner.newTerm(Position.NOPOS, sflags, name);
            Type type = pool.getFieldType(in.nextChar());
            symbol.setInfo(type);
            attrib.readAttributes(symbol, type, FIELD_ATTR);
            getScope(jflags).enterOrOverload(symbol);
        }
    }

    /** read a method
     */
    protected void parseMethod() {
        int jflags = in.nextChar();
        int sflags = transFlags(jflags);
        if ((jflags & JAVA_ACC_BRIDGE) != 0) sflags |= Modifiers.PRIVATE;
        if ((sflags & Modifiers.PRIVATE) != 0) {
            in.skip(4);
            attrib.skipAttributes();
        } else {
            Name name = pool.getName(in.nextChar());
            Type type = pool.getMethodType(in.nextChar());
            Symbol owner = getOwner(jflags);
            Symbol symbol;
            boolean newConstructor = false;
            if (name == CONSTR_N) {
                switch (type) {
                case MethodType(Symbol[] vparams, _):
                    type = Type.MethodType(vparams, ctype);
                    break;
                default:
                    throw Debug.abort("illegal case", type);
                }
                symbol = owner.primaryConstructor();
                if (symbol.isInitialized()) {
                    symbol = owner.newConstructor(Position.NOPOS, sflags);
                    newConstructor = true;
                } else {
                    symbol.flags = sflags;
                }
            } else {
                symbol = owner.newTerm(Position.NOPOS, sflags, name);
            }
            setParamOwners(type, symbol);
            symbol.setInfo(type);
            attrib.readAttributes(symbol, type, METH_ATTR);
            if (name != CONSTR_N) {
                if ((symbol.flags & Modifiers.BRIDGE) == 0)
                    getScope(jflags).enterOrOverload(symbol);
            } else if (newConstructor)
                owner.addConstructor(symbol);
        }
    }

    /** return the owner of a member with given java flags
     */
    private Symbol getOwner(int jflags) {
        return (jflags & JAVA_ACC_STATIC) != 0 ? m.moduleClass() : c;
    }

    /** return the scope of a member with given java flags
     */
    private Scope getScope(int jflags) {
        return (jflags & JAVA_ACC_STATIC) != 0 ? statics : locals;
    }

    private void setParamOwners(Type type, Symbol owner) {
        switch (type) {
            case PolyType(Symbol[] params, Type result):
				for (int i = 0; i < params.length; i++)
					params[i].setOwner(owner);
				setParamOwners(result, owner);
				break;
			case MethodType(Symbol[] params, Type result):
				for (int i = 0; i < params.length; i++) params[i].setOwner(owner);
				setParamOwners(result, owner);
				break;
		}
    }
}