/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.vm.bytecode; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashSet; import java.util.List; /** * @author Ewout Prangsma (epr@users.sourceforge.net) */ public class BytecodeWriter { private final ByteBuffer code; private HashSet<Label> labels; public BytecodeWriter(int capacity) { this.code = ByteBuffer.allocate(capacity); } public ByteBuffer toByteBuffer() { // Test all labels, they must have been resolved if (labels != null) { for (Label l : labels) { if (!l.isResolved()) { throw new RuntimeException("Unresolved label " + l); } } } if (code.limit() > 0) { return (ByteBuffer) code.duplicate().rewind(); } else { return null; } } public Label newLabel(String text) { final Label l = new Label(text); if (labels == null) { labels = new HashSet<Label>(); } labels.add(l); return l; } public void clear() { code.rewind().limit(0); if (labels != null) { labels.clear(); } } public void aaload() { write8(0x32); } public void aastore() { write8(0x53); } public void aconst_null() { write8(0x01); } public void aload(int index) { if ((index >= 0) && (index <= 3)) { write8(0x2A + index); } else { write8(0x19); write8(index); } } public void anewarray(int index) { write8(0xbd); write16(index); } public void areturn() { write8(0xb0); } public void arraylength() { write8(0xbe); } public void astore(int index) { if ((index >= 0) && (index <= 3)) { write8(0x4b + index); } else { write8(0x3a); write8(index); } } public void athrow() { write8(0xbf); } public void baload() { write8(0x33); } public void bastore() { write8(0x54); } public void bipush() { write8(0x10); } public void caload() { write8(0x34); } public void castore() { write8(0x55); } public void checkcast() { write8(0xc0); } public void d2f() { write8(0x90); } public void d2i() { write8(0x8e); } public void d2l() { write8(0x8f); } public void dadd() { write8(0x63); } public void daload() { write8(0x31); } public void dastore() { write8(0x52); } public void dcmpg() { write8(0x98); } public void dcmpl() { write8(0x97); } public void dconst_0() { write8(0x0e); } public void dconst_1() { write8(0x0f); } public void ddiv() { write8(0x6f); } public void dload(int index) { if ((index >= 0) && (index <= 3)) { write8(0x26 + index); } else { write8(0x18); write8(index); } } public void dmul() { write8(0x6b); } public void dneg() { write8(0x77); } public void drem() { write8(0x73); } public void dreturn() { write8(0xaf); } public void dstore(int index) { if ((index >= 0) && (index <= 3)) { write8(0x39 + index); } else { write8(0x47); write8(index); } } public void dsub() { write8(0x67); } public void dup() { write8(0x59); } public void dup_x1() { write8(0x5a); } public void dup_x2() { write8(0x5b); } public void dup2() { write8(0x5c); } public void dup2_x1() { write8(0x5d); } public void dup2_x2() { write8(0x5e); } public void f2d() { write8(0x8d); } public void f2i() { write8(0x8b); } public void f2l() { write8(0x8c); } public void fadd() { write8(0x62); } public void faload() { write8(0x30); } public void fastore() { write8(0x51); } public void fcmpg() { write8(0x96); } public void fcmpl() { write8(0x95); } public void fconst_0() { write8(0x0b); } public void fconst_1() { write8(0x0c); } public void fconst_2() { write8(0x0d); } public void fdiv() { write8(0x6e); } public void fload(int index) { if ((index >= 0) && (index <= 3)) { write8(0x22 + index); } else { write8(0x17); write8(index); } } public void fmul() { write8(0x6a); } public void fneg() { write8(0x76); } public void frem() { write8(0x72); } public void freturn() { write8(0xae); } public void fstore(int index) { if ((index >= 0) && (index <= 3)) { write8(0x43 + index); } else { write8(0x38); write8(index); } } public void fsub() { write8(0x66); } public void getfield(int index) { write8(0xb4); write16(index); } public void getstatic(int index) { write8(0xb2); write16(index); } public void goto_(Label label) { final int start = code.position(); write8(0xa7); write16(start, label); } /*public void goto_w(Label label) { write8(0xc8); write32(label); }*/ public void i2b() { write8(0x91); } public void i2c() { write8(0x92); } public void i2d() { write8(0x87); } public void i2f() { write8(0x86); } public void i2l() { write8(0x85); } public void i2s() { write8(0x93); } public void iadd() { write8(0x60); } public void iaload() { write8(0x2e); } public void iand() { write8(0x7e); } public void iastore() { write8(0x4f); } public void iconst_m1() { write8(0x02); } public void iconst_0() { write8(0x03); } public void iconst_1() { write8(0x04); } public void iconst_2() { write8(0x05); } public void iconst_3() { write8(0x06); } public void iconst_4() { write8(0x07); } public void iconst_5() { write8(0x08); } public void idiv() { write8(0x6c); } public void if_acmpeq(Label label) { final int start = code.position(); write8(0xa5); write16(start, label); } public void if_acmpne(Label label) { final int start = code.position(); write8(0xa6); write16(start, label); } public void if_icmpeq(Label label) { final int start = code.position(); write8(0x97); write16(start, label); } public void if_icmpne(Label label) { final int start = code.position(); write8(0xa0); write16(start, label); } public void if_icmplt(Label label) { final int start = code.position(); write8(0xa1); write16(start, label); } public void if_icmpge(Label label) { final int start = code.position(); write8(0xa2); write16(start, label); } public void if_icmpgt(Label label) { final int start = code.position(); write8(0xa3); write16(start, label); } public void if_icmple(Label label) { final int start = code.position(); write8(0xa4); write16(start, label); } public void ifeq(Label label) { final int start = code.position(); write8(0x99); write16(start, label); } public void ifne(Label label) { final int start = code.position(); write8(0x9a); write16(start, label); } public void iflt(Label label) { final int start = code.position(); write8(0x9b); write16(start, label); } public void ifge(Label label) { final int start = code.position(); write8(0x9c); write16(start, label); } public void ifgt(Label label) { final int start = code.position(); write8(0x9d); write16(start, label); } public void ifle(Label label) { final int start = code.position(); write8(0x9e); write16(start, label); } public void ifnonnull(Label label) { final int start = code.position(); write8(0xc7); write16(start, label); } public void ifnull(Label label) { final int start = code.position(); write8(0xc6); write16(start, label); } public void iinc(int index, int constValue) { write8(0x84); write8(index); write8(constValue); } public void iload(int index) { if ((index >= 0) && (index <= 3)) { write8(0x1a + index); } else { write8(0x15); write8(index); } } public void imul() { write8(0x68); } public void ineg() { write8(0x74); } public void instanceof_(int index) { write8(0xc1); write16(index); } public void invokeinterface(int index, int count) { write8(0xb9); write16(index); write8(count); write8(0); } public void invokespecial(int index) { write8(0xb7); write16(index); } public void invokestatic(int index) { write8(0xb8); write16(index); } public void invokevirtual(int index) { write8(0xb6); write16(index); } public void ior() { write8(0x80); } public void irem() { write8(0x70); } public void ireturn() { write8(0xac); } public void ishl() { write8(0x78); } public void ishr() { write8(0x7a); } public void istore(int index) { if ((index >= 0) && (index <= 3)) { write8(0x3b + index); } else { write8(0x54); write8(index); } } public void isub() { write8(0x64); } public void iushr() { write8(0x7c); } public void ixor() { write8(0x82); } public void jsr(Label label) { final int start = code.position(); write8(0xa8); write16(start, label); } /*public void jsr_w(Label label) { write8(0xc9); write32(label); }*/ public void l2d() { write8(0x8a); } public void l2f() { write8(0x89); } public void l2i() { write8(0x88); } public void ladd() { write8(0x61); } public void laload() { write8(0x2f); } public void land() { write8(0x7f); } public void lastore() { write8(0x50); } public void lcmp() { write8(0x94); } public void lconst_0() { write8(0x09); } public void lconst_1() { write8(0x0a); } public void ldc(int index) { write8(0x12); write8(index); } public void ldc_w(int index) { write8(0x13); write16(index); } public void ldc2_w(int index) { write8(0x14); write16(index); } public void ldiv() { write8(0x6d); } public void lload(int index) { if ((index >= 0) && (index <= 3)) { write8(0x1e + index); } else { write8(0x16); write8(index); } } public void lmul() { write8(0x69); } public void lneg() { write8(0x75); } /*public void lookupswitch(int defaultBranch, int[] branches) { // Not implemented yet }*/ public void lor() { write8(0x81); } public void lrem() { write8(0x71); } public void lreturn() { write8(0xad); } public void lshl() { write8(0x79); } public void lshr() { write8(0x7b); } public void lstore(int index) { if ((index >= 0) && (index <= 3)) { write8(0x3f + index); } else { write8(0x37); write8(index); } } public void lsub() { write8(0x65); } public void lxor() { write8(0x83); } public void monitorenter() { write8(0xc2); } public void monitorexit() { write8(0xc3); } public void multianewarray(int index, int dims) { write8(0xc5); write16(index); write8(dims); } public void new_(int index) { write8(0xbb); write16(index); } public void newarray(int atype) { write8(0xbc); write8(atype); } public void nop() { write8(0x00); } public void pop() { write8(0x57); } public void pop2() { write8(0x58); } public void putfield(int index) { write8(0xb5); write16(index); } public void putstatic(int index) { write8(0xb3); write16(index); } public void ret(int index) { write8(0xa9); write8(index); } public void return_() { write8(0xb1); } public void saload() { write8(0x53); } public void sastore() { write8(0x56); } public void sipush(int index) { write8(0x11); write16((short) index); } public void swap() { write8(0x5f); } /*public void tableswitch(int defaultBranch, int low, int high, int[] branches) { write8(0xaa); }*/ private final void ensureSpace(int extra) { final int size = code.position() + extra; if (code.limit() < size) { code.limit(size); } } /** * Write an 8-bit int * * @param v */ private final void write8(int v) { ensureSpace(1); code.put((byte) (v & 0xFF)); } /** * Write an 16-bit int * * @param v */ private final void write16(int v) { ensureSpace(2); code.put((byte) ((v >> 8) & 0xFF)); code.put((byte) (v & 0xFF)); } /** * Write an 16-bit branch * * @param insStart * @param label */ private final void write16(int insStart, Label label) { if (label.isResolved()) { write16(label.getAddress() - insStart); } else { label.addUnresolvedLocation(code.position()); write16(code.position() - insStart); } } /** * Write an 32-bit int * @param v */ /*private final void write32(int v) { ensureSpace(4); set32(code, used, v); used += 4; }*/ /** * Set an 8-bit int * * @param code * @param ofs * @param v */ public static final void set8(ByteBuffer code, int ofs, int v) { code.put(ofs, (byte) (v & 0xFF)); } /** * Set an 16-bit int * * @param code * @param ofs * @param v */ public static final void set16(ByteBuffer code, int ofs, int v) { code.put(ofs++, (byte) ((v >> 8) & 0xFF)); code.put(ofs++, (byte) (v & 0xFF)); } /** * Set an 32-bit int * * @param code * @param ofs * @param v */ public static final void set32(ByteBuffer code, int ofs, int v) { code.put(ofs++, (byte) ((v >> 24) & 0xFF)); code.put(ofs++, (byte) ((v >> 16) & 0xFF)); code.put(ofs++, (byte) ((v >> 8) & 0xFF)); code.put(ofs++, (byte) (v & 0xFF)); } /** * Get an 8-bit int * * @param code * @param ofs * @return int */ public static final int get8(ByteBuffer code, int ofs) { return code.get(ofs) & 0xFF; } /** * Set an 16-bit int * * @param code * @param ofs * @return int */ public static final int get16(ByteBuffer code, int ofs) { final int v1 = code.get(ofs++) & 0xFF; final int v2 = code.get(ofs) & 0xFF; return (v1 << 8) | v2; } /** * Get an 32-bit int * * @param code * @param ofs * @return int */ public static final int get32(ByteBuffer code, int ofs) { final int v1 = code.get(ofs++) & 0xFF; final int v2 = code.get(ofs++) & 0xFF; final int v3 = code.get(ofs++) & 0xFF; final int v4 = code.get(ofs) & 0xFF; return (v1 << 24) | (v2 << 16) | (v3 << 8) | v4; } public final int getLength() { return code.position(); } final ByteBuffer getCode() { return (ByteBuffer) code.duplicate().rewind(); } class Label { private final String text; private List<Integer> unresolvedLocations; private int address = -1; Label(String text) { this.text = text; } public String toString() { return text; } public boolean isResolved() { return (address >= 0); } public int getAddress() { if (address < 0) { throw new RuntimeException("Not resolved yet"); } return address; } void addUnresolvedLocation(int loc) { if (isResolved()) { throw new RuntimeException("Already resolved"); } if (unresolvedLocations == null) { unresolvedLocations = new ArrayList<Integer>(); } unresolvedLocations.add(loc); } public void resolve() { if (isResolved()) { throw new RuntimeException("Cannot resolve twice"); } this.address = getLength(); if (unresolvedLocations != null) { for (int loc : unresolvedLocations) { final int distance = address - get16(getCode(), loc); set16(getCode(), loc, distance); } unresolvedLocations = null; } } } }