summaryrefslogblamecommitdiff
path: root/sources/scalac/symtab/classfile/UnPickle.java
blob: eed1fdc00a2d6fb0e818cf2f64e96c7ff24f6571 (plain) (tree)

































































































































































































































































































































































































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

// $Id$

package scalac.symtab.classfile;

import java.util.HashMap;
import scalac.*;
import scalac.util.*;
import ch.epfl.lamp.util.Position;
import scalac.symtab.*;
import Symbol.*;
import Type.*;

public class UnPickle implements Kinds, Modifiers, EntryTags {

/***************************************************
 * Symbol table attribute format:
 *   Symtab         = nentries_Nat {Entry}
 *   Entry          = TERMNAME len_Nat NameInfo
 *                  | CONSTRNAME len_Nat NameInfo
 *                  | TYPENAME len_Nat NameInfo
 *                  | NONEsym len_Nat
 *                  | TYPEsym len_Nat SymbolInfo lobound_Ref
 *                  | ALIASsym len_Nat SymbolInfo
 *                  | CLASSsym len_Nat SymbolInfo thistype_Ref constrsym_Ref
 *                  | MODULEsym len_Nat SymbolInfo classsym_Ref
 *                  | VALsym len_Nat SymbolInfo [classsym_Ref]
 *                  | EXTsym len_Nat name_Ref [owner_Ref]
 *                  | NOtpe len_Nat
 *                  | THIStpe len_Nat sym_Ref
 *                  | SINGLEtpe len_Nat type_Ref sym_Ref
 *                  | TYPEREFtpe len_Nat type_Ref sym_Ref {targ_Ref}
 *                  | COMPOUNDtpe len_Nat sym_Ref {tpe_Ref} {sym_Ref}
 *                  | METHODtpe len_Nat tpe_Ref {tpe_Ref}
 *                  | POLYTtpe len_Nat tpe_Ref {sym_Ref}
 *                  | OVERLOADEDtpe len_Nat {sym_Ref} {tpe_Ref}
 *   SymbolInfo     = name_Ref owner_Ref flags_Nat info_Ref
 *   NameInfo       = <character sequence of length len_Nat in Utf8 format>
 *   Ref            = Nat
 *
 *   len is remaining length after `len'.
 */
    static final boolean debug = false;

    Symbol classroot;
    Symbol moduleroot;
    byte[] bytes;
    int bp;
    Name sourceName;
    int[] index;
    Object[] entries;

    UnPickle(Symbol root, byte[] data, Name sourceName) {
	assert root.rawInfoAt(Symbol.FIRST_ID) instanceof LazyType;
	//System.out.println("unpickle " + root);//DEBUG
	this.classroot = root;
	this.moduleroot = classroot.module();
	this.bytes = data;
	this.bp = 0;
	this.sourceName = sourceName;
	index = new int[readNat()];
	for (int i = 0; i < index.length; i++) {
	    index[i] = bp;
	    bp++;
	    bp = readNat() + bp;
	}
	entries = new Object[index.length];
	if (debug) {
	    for (int i = 0; i < index.length; i++) {
		System.out.print(i + "," + index[i] + ": ");
		bp = index[i];
		System.out.print(readByte() + " ");
		int len = readNat();
		System.out.print(len + " ");
		for (int j = 0; j < len; j++)
		    System.out.print(readByte() + " ");
		System.out.println();
	    }
	}
	for (int i = 0; i < index.length; i++) {
	    if (isSymbolEntry(i)) getSymbol(i);
	}
	if (root.rawInfoAt(Symbol.FIRST_ID) instanceof LazyType)
	    throw new BadSignature(this, "it does not define " + root);
    }

    Type setOwner(Type tp, Symbol owner) {
	switch (tp) {
	case PolyType(Symbol[] tparams, Type restpe):
	    Type restpe1 = setOwner(restpe, owner);
	    if (restpe1 == restpe) return tp;
	    else return Type.PolyType(tparams, restpe1);
	case MethodType(Symbol[] params, Type restpe):
	    Symbol[] params1 = params;
	    for (int i = 0; i < params.length; i++) {
		if (params[i].owner() != owner) {
		    if (params1 == params && params[i].owner() != Symbol.NONE) {
			params1 = new Symbol[params.length];
			System.arraycopy(params, 0, params1, 0, i);
		    }
		    params1[i].setOwner(owner);
		}
	    }
	    Type restpe1 = setOwner(restpe, owner);
	    if (params1 == params && restpe1 == restpe) return tp;
	    else return Type.MethodType(params1, restpe1);
	default:
	    return tp;
	}
    }

    int readByte() {
	return bytes[bp++];
    }

    int readNat() {
	int b;
	int x = 0;
	do {
	    b = readByte();
	    x = (x << 7) + (b & 0x7f);
	} while ((b & 0x80) != 0);
	return x;
    }

    boolean isTypeEntry(int i) {
	int tag = bytes[index[i]];
	return (firstTypeTag <= tag && tag <= lastTypeTag);
    }

    boolean isSymbolEntry(int i) {
	int tag = bytes[index[i]];
	return (firstSymTag <= tag && tag <= lastSymTag);
    }

    Name getName(int n) {
	if (entries[n] == null) {
	    int savedBp = bp;
	    bp = index[n];
	    int tag = bytes[bp++];
	    int len = readNat();
	    Name name = Name.fromAscii(bytes, bp, len);
	    switch (tag) {
	    case TERMname  : entries[n] = name; break;
	    case CONSTRname: entries[n] = name.toConstrName(); break;
	    case TYPEname  : entries[n] = name.toTypeName(); break;
	    default: throw new BadSignature(this);
	    }
	    bp = savedBp;
	}
	return (Name) entries[n];
    }

    Name readNameRef() {
	return getName(readNat());
    }

    Symbol getSymbol(int n) {
	if (entries[n] == null) {
	    int savedBp = bp;
	    bp = index[n];
	    int tag = bytes[bp++];
	    int end = readNat() + bp;
	    Symbol sym;
	    Symbol owner;
	    switch (tag) {
	    case NONEsym:
		entries[n] = sym = Symbol.NONE;
		break;
	    case EXTsym:
		Name name = readNameRef();
		if (bp == end) {
		    owner = Global.instance.definitions.ROOT_CLASS;
		} else {
		    assert bp < end;
		    owner = readSymbolRef();
		}
		if (name.length() == 0 && owner == Symbol.NONE) {
		    entries[n] = sym = Global.instance.definitions.ROOT_CLASS;
		} else {
		    entries[n] = sym = owner.info().lookupNonPrivate(name);
		}
		if (sym.kind == NONE) {
		    throw new BadSignature(this,
			"reference " + name + " of " + owner +
			" refers to nonexisting symbol.");
		}
		break;
	    default:
		assert isSymbolEntry(n) : n;
		Name name = readNameRef();
		owner = readSymbolRef();
		if (entries[n] == null) {
		    int flags = readNat();
		    int inforef = readNat();
		    switch (tag) {
		    case TYPEsym:
			entries[n] = sym = new AbsTypeSymbol(
			    Position.NOPOS, name, owner, flags);
			sym.setInfo(getType(inforef));
			sym.setLoBound(readTypeRef());
			break;

		    case ALIASsym:
			entries[n] = sym = new TypeSymbol(
			    ALIAS, Position.NOPOS, name, owner, flags);
			sym.setInfo(getType(inforef));
			break;

		    case CLASSsym:
			entries[n] = sym = new ClassSymbol(
			    Position.NOPOS, name, owner, flags);
			if (name == classroot.name && owner == classroot.owner()) {
			    sym.copyTo(classroot);
			    entries[n] = sym = classroot;
			}
			sym.setInfo(getType(inforef));
			sym.setTypeOfThis(readTypeRef());
			Symbol constructor = readSymbolRef(); //will install itself!
			break;

		    case MODULEsym:
			entries[n] = sym = TermSymbol.newModule(
			    Position.NOPOS, name, owner, flags, (ClassSymbol) readSymbolRef());
			if (name == moduleroot.name && owner == moduleroot.owner()) {
			    sym.copyTo(moduleroot);
			    entries[n] = sym = moduleroot;
			}
			sym.setInfo(getType(inforef));
			break;

		    case VALsym:
			if (bp < end) {
			    assert name.isConstrName();
			    Symbol clazz = readSymbolRef();
			    entries[n] = sym = clazz.constructor();
			    TermSymbol.newConstructor(clazz, flags).copyTo(sym);
			} else {
			    entries[n] = sym = new TermSymbol(
				Position.NOPOS, name, owner, flags);
			}
			sym.setInfo(setOwner(getType(inforef), sym));
			break;

		    default:
			throw new BadSignature(this);
		    }

		    if (owner.kind == CLASS &&
			!(sym == classroot ||
			  sym.kind == CLASS && (sym.flags & MODUL) != 0 ||
			  (sym.isPrimaryConstructor() &&
			   (sym.primaryConstructorClass().flags & MODUL) != 0)))
			owner.members().enter(sym);
		}
	    }
	    bp = savedBp;
	}
	return (Symbol) entries[n];
    }

    Symbol readSymbolRef() {
	return getSymbol(readNat());
    }

    Symbol[] readSymbolRefs(int end) {
	return readSymbolRefs(0, end);
    }

    Symbol[] readSymbolRefs(int nread, int end) {
	if (bp == end) {
	    return new Symbol[nread];
	} else {
	    assert bp < end;
	    int ref = readNat();
	    if (isSymbolEntry(ref)) {
		Symbol s = getSymbol(ref);
		Symbol[] ss = readSymbolRefs(nread+1, end);
		ss[nread] = s;
		return ss;
	    } else {
		return new Symbol[nread];
	    }
	}
    }

    Type getType(int n) {
	if (entries[n] == null) {
	    int savedBp = bp;
	    bp = index[n];
	    int tag = bytes[bp++];
	    int end = readNat() + bp;
	    Type tpe;
	    switch (tag) {
	    case NOtpe:
		tpe = Type.NoType;
		break;
	    case THIStpe:
		tpe = Type.ThisType(readSymbolRef());
		break;
	    case SINGLEtpe:
		tpe = Type.singleType(readTypeRef(), readSymbolRef());
		break;
	    case TYPEREFtpe:
		tpe = Type.TypeRef(
		    readTypeRef(), readSymbolRef(), readTypeRefs(end));
		break;
	    case COMPOUNDtpe:
		Symbol clazz = readSymbolRef();
		Type[] parents = readTypeRefs(end);
		Scope members = new Scope(readSymbolRefs(end));
		tpe = Type.compoundType(parents, members, clazz);
		break;
	    case METHODtpe:
		Type restype = readTypeRef();
		Type[] argtypes = readTypeRefs(end);
		Symbol[] params = new Symbol[argtypes.length];
		for (int i = 0; i < argtypes.length; i++) {
		    params[i] = new TermSymbol(
			Position.NOPOS, Name.fromString("$" + i),
			Symbol.NONE, PARAM);
		    params[i].setInfo(argtypes[i]);
		}
		tpe = Type.MethodType(params, restype);
		break;
	    case POLYtpe:
		Type restype = readTypeRef();
		tpe = Type.PolyType(readSymbolRefs(end), restype);
		break;
	    case OVERLOADEDtpe:
		Symbol[] alts = readSymbolRefs(end);
		Type[] alttypes = readTypeRefs(end);
		for (int i = 0; i < alts.length; i++)
		    alttypes[i] = setOwner(alttypes[i], alts[i]);
		tpe = Type.OverloadedType(alts, alttypes);
		break;
	    default:
		throw new BadSignature(this);
	    }
	    entries[n] = tpe;
	    bp = savedBp;
	}
	return (Type) entries[n];
    }

    Type readTypeRef() {
	return getType(readNat());
    }

    Type[] readTypeRefs(int end) {
	return readTypeRefs(0, end);
    }

    Type[] readTypeRefs(int nread, int end) {
	if (bp == end) {
	    return new Type[nread];
	} else {
	    assert bp < end;
	    int ref = readNat();
	    if (isTypeEntry(ref)) {
		Type t = getType(ref);
		Type[] ts = readTypeRefs(nread + 1, end);
		ts[nread] = t;
		return ts;
	    } else {
		return new Type[nread];
	    }
	}
    }

    public static class BadSignature extends java.lang.Error {
	public BadSignature(UnPickle outer, String msg) {
	    super("symbol data " + outer.sourceName +
		  " could not be loaded; " + msg);
	}
	public BadSignature(UnPickle outer) {
	    this(outer, "malformed signature at " + outer.bp);
	}
    }
}