/* * This file is a part of Alchemy OS project. * Copyright (C) 2011-2014, Sergey Basalaev <sbasalaev@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package alchemy.evm; import alchemy.system.Function; import alchemy.system.Library; import alchemy.system.Process; import alchemy.types.Float32; import alchemy.types.Float64; import alchemy.types.Int32; import alchemy.types.Int64; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; /** * Loads Ether libraries. * @author Sergey Basalaev */ public final class EtherLoader { private EtherLoader() { } /** * Highest supported library format. * <ul> * <li> * Two highest bytes are zeroes. * <li> * Byte 1 is MAJOR version. Formats with two different * major versions are incompatible. * <li> * Byte 0 is MINOR version. Formats with the same major * version are backward compatible, that is file's minor * version must be equal to or less than this value. * </ul> */ static public final int VERSION = 0x0202; /* * New in format 1.1 * Instructions: call calv newarray aload astore alen newba * baload bastore balen newca caload castore calen * * New in format 2.0 * Simplify format to be loaded and processed faster * Add line number table to functions * Add error table to functions * Instructions: if_icmpge if_icmpgt if_icmple if_icmplt * tableswitch lookupswitch * * New in format 2.1 * Cast instructions: i2c * Array instructions: newza zaload zastore zalen newsa saload * sastore salen newia iaload iastore ialen newla laload lastore * lalen newfa faload fastore falen newda daload dastore dalen * Jump instructions: jsr ret if_acmpeq if_acmpne * Variable instructions: iinc * * New in format 2.2 * Call instructions: callc callc_n calvc calvc_n * Global var access: getglobal getglobaldef setglobal * Other instructions: throw newmultiarray concat */ /** Loads Ether library from given input stream. */ public static Library load(Process p, InputStream in) throws IOException, InstantiationException { DataInputStream data = new DataInputStream(in); Library lib; //reading format version int ver = data.readUnsignedShort(); if ((ver | 0xff) != (VERSION | 0xff) || (ver & 0xff) > (VERSION & 0xff)) throw new InstantiationException("Incompatible executable format: "+ver); //reading object type int lflags = data.readUnsignedByte(); //reading soname if ((lflags & Opcodes.LFLAG_SONAME) != 0) { lib = new Library(data.readUTF()); } else { lib = new Library(); } //loading dependency libs Library[] libdeps = null; if ((lflags & Opcodes.LFLAG_DEPS) != 0) { int depcount = data.readUnsignedShort(); libdeps = new Library[depcount]; for (int i=0; i<depcount; i++) { libdeps[i] = p.loadLibrary(data.readUTF()); } } //constructing constant pool int ccount = data.readUnsignedShort(); Object[] cpool = new Object[ccount]; for (int cindex=0; cindex<ccount; cindex++) { int ctype = data.readUnsignedByte(); switch (ctype) { case '0': //null, aligning object break; case 'i': //integer cpool[cindex] = Int32.toInt32(data.readInt()); break; case 'l': //long cpool[cindex] = new Int64(data.readLong()); break; case 'f': //float cpool[cindex] = new Float32(data.readFloat()); break; case 'd': //double cpool[cindex] = new Float64(data.readDouble()); break; case 'S': //string cpool[cindex] = data.readUTF(); break; case 'E': { //external function int libref = data.readUnsignedShort(); String name = data.readUTF(); cpool[cindex] = libdeps[libref].getFunction(name); } break; case 'P': { // function //reading data String fname = data.readUTF(); int fflags = data.readUnsignedByte(); int stacksize = data.readUnsignedByte(); int localsize = data.readUnsignedByte(); int codesize = data.readUnsignedShort(); byte[] code = new byte[codesize]; char[] lnumtable = null; char[] errtable = null; data.readFully(code); if ((fflags & Opcodes.FFLAG_RELOCS) != 0) { data.skipBytes(data.readUnsignedShort()*2); } if ((fflags & Opcodes.FFLAG_LNUM) != 0) { lnumtable = new char[data.readUnsignedShort()]; for (int j=0; j < lnumtable.length; j++) { lnumtable[j] = data.readChar(); } } if ((fflags & Opcodes.FFLAG_ERRTBL) != 0) { errtable = new char[data.readUnsignedShort()]; for (int j=0; j < errtable.length; j++) { errtable[j] = data.readChar(); } } //constructing function Function func = new EtherFunction(lib, fname, cpool, stacksize, localsize, code, lnumtable, errtable); cpool[cindex] = func; if ((fflags & Opcodes.FFLAG_SHARED) != 0) lib.putFunction(func); } break; default: throw new InstantiationException("Unknown data type: "+ctype); } } return lib; } }