summaryrefslogblamecommitdiff
path: root/sources/scalac/symtab/classfile/ClassfileParser.java
blob: 9debd17b0f201eabb32c684446ea9f1de252d9f5 (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 ch.epfl.lamp.util.Position;
import scalac.*;
import scalac.util.*;
import scalac.symtab.*;
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;
    static final int METH_ATTR   = CODE_ATTR
                                 | EXCEPTIONS_ATTR
                                 | SYNTHETIC_ATTR
                                 | DEPRECATED_ATTR
                                 | META_ATTR;
    static final int FIELD_ATTR  = CONSTANT_VALUE_ATTR
                                 | SYNTHETIC_ATTR
                                 | DEPRECATED_ATTR
                                 | META_ATTR;

    protected Global global;
    protected AbstractFileReader in;
    protected Symbol c;
    protected Type ctype;
    protected Scope locals;
    protected Scope statics;
    protected JavaTypeFactory make;
    protected Signatures sigs;
    protected ConstantPool pool;
    protected AttributeParser attrib;
    protected Definitions defs;


    public ClassfileParser(Global global, AbstractFileReader in, Symbol c) {
        this.global = global;
        this.in = in;
        this.c = c;
        this.ctype = c.typeConstructor();
        this.make = new JavaTypeCreator(global);
        this.sigs = new Signatures(global, make);
        this.pool = new ConstantPool(in, sigs);
        this.attrib = new AttributeParser(in, pool, this);
        this.defs = global.definitions;
    }


    /** parse the classfile and throw IO exception if there is an
     *  error in the classfile structure
     */
    public void parse() throws IOException {
        try {
            if (in.nextInt() != JAVA_MAGIC)
                throw new IOException("illegal start of class file");
            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 has wrong version " +
                        majorVersion + "." + minorVersion + ", should be " +
                        JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION);
            pool.indexPool();
            int flags = in.nextChar();
            Name name = readClassName(in.nextChar());
            if (c.fullName() != name)
                throw new IOException("class file '" + c.fullName() +
                                      "' contains wrong class " + name);
            // 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];
            this.locals = new Scope();
            this.statics = new Scope();
            // set type of class
            Type classType = Type.compoundType(basetpes, locals, c);
            c.setFirstInfo(classType);
            // set type of statics
            Symbol staticsClass = c.module().moduleClass();
            if (staticsClass.isModuleClass()) {
                Type staticsInfo = Type.compoundType(Type.EMPTY_ARRAY, statics, staticsClass);
                staticsClass.setFirstInfo(staticsInfo);
                c.module().setInfo(Type.TypeRef(staticsClass.owner().thisType(),
                                            staticsClass, Type.EMPTY_ARRAY));
            }
            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.setFirstInfo(
                    Type.MethodType(Symbol.EMPTY_ARRAY, ctype));
                if ((c.flags & Modifiers.INTERFACE) == 0)
                    constr.flags |= Modifiers.PRIVATE;
            }
            attrib.readAttributes(c, classType, CLASS_ATTR);
            //System.out.println("dynamic class: " + c);
            //System.out.println("statics class: " + staticsClass);
            //System.out.println("module: " + c.module());
            //System.out.println("modules class: " + c.module().type().symbol());
        } catch (RuntimeException e) {
            if (global.debug) e.printStackTrace();
            String s = e.getMessage() == null ? "" : " (" +e.getMessage()+ ")";
            throw new IOException("bad class file" + s);
        }
    }

    /** convert Java modifiers into Scala flags
     */
    public int transFlags(int flags) {
        int res = 0;
        if (((flags & 0x0007) == 0) ||
            ((flags & 0x0002) != 0))
            res |= Modifiers.PRIVATE;
        else if ((flags & 0x0004) != 0)
            res |= Modifiers.PROTECTED;
        if ((flags & 0x0400) != 0)
            res |= Modifiers.DEFERRED;
        if ((flags & 0x0010) != 0)
            res |= Modifiers.FINAL;
        if ((flags & 0x0200) != 0)
            res |= Modifiers.INTERFACE | Modifiers.TRAIT | Modifiers.ABSTRACT;
        return res | Modifiers.JAVA;
    }

    /** read a class name
     */
    protected Name readClassName(int i) {
        return (Name)pool.readPool(i);
    }

    /** read a class name and return the corresponding class type
     */
    protected Type readClassType(int i) {
        if (i == 0)
            return defs.ANY_TYPE;
        Type res = defs.getJavaType((Name)pool.readPool(i));
        if (res == Type.ErrorType)
            global.error("unknown class reference " + pool.readPool(i));
        return res;
    }

    /** read a signature and return it as a type
     */
    protected Type readType(int i) {
        Name sig = pool.readExternal(i);
        return sigs.sigToType(Name.names, sig.index, sig.length());
    }

    /** read a field
     */
    protected void parseField() {
        int flags = in.nextChar();
        Name name = (Name)pool.readPool(in.nextChar());
        Type type = readType(in.nextChar());
        int mods = transFlags(flags);
        if ((flags & 0x0010) == 0)
            mods |= Modifiers.MUTABLE;
        Symbol owner = c;
        if ((flags & 0x0008) != 0)
            owner = c.module().moduleClass();
        Symbol s = new TermSymbol(Position.NOPOS, name, owner, mods);
        s.setFirstInfo(type);
        attrib.readAttributes(s, type, FIELD_ATTR);
        ((flags & 0x0008) != 0 ? statics : locals).enterOrOverload(s);
    }

    /** read a method
     */
    protected void parseMethod() {
        int flags = in.nextChar();
        Name name = (Name)pool.readPool(in.nextChar());
        Type type = readType(in.nextChar());
        if (CONSTR_N.equals(name)) {
            Symbol s = TermSymbol.newConstructor(c, transFlags(flags));
            // kick out package visible or
            // private constructors
            if (((flags & 0x0002) != 0) ||
                ((flags & 0x0007) == 0)) {
                attrib.readAttributes(s, type, METH_ATTR);
                return;
            }
            switch (type) {
            case MethodType(Symbol[] vparams, _):
                type = Type.MethodType(vparams, ctype);
                break;
            default:
                throw new ApplicationError();
            }
            s.setFirstInfo(type);
            attrib.readAttributes(s, type, METH_ATTR);
            Symbol constr = c.primaryConstructor();
            if (constr.isInitialized()) constr = c.addConstructor();
            s.copyTo(constr);
            //System.out.println(c + " " + c.allConstructors() + ":" + c.allConstructors().info());//debug
            //System.out.println("-- enter " + s);
        } else {
            Symbol s = new TermSymbol(
                Position.NOPOS, name,
                ((flags & 0x0008) != 0) ? c.module().moduleClass() : c,
                transFlags(flags));
            s.setFirstInfo(type);
            attrib.readAttributes(s, type, METH_ATTR);
            ((flags & 0x0008) != 0 ? statics : locals).enterOrOverload(s);
        }
    }
}