diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/share/classes/com/sun/tools/jdi/PacketStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/tools/jdi/PacketStream.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,628 @@ +/* + * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.jdi; + +import com.sun.jdi.*; +import java.util.*; +import java.io.ByteArrayOutputStream; + +class PacketStream { + final VirtualMachineImpl vm; + private int inCursor = 0; + final Packet pkt; + private ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); + private boolean isCommitted = false; + + PacketStream(VirtualMachineImpl vm, int cmdSet, int cmd) { + this.vm = vm; + this.pkt = new Packet(); + pkt.cmdSet = (short)cmdSet; + pkt.cmd = (short)cmd; + } + + PacketStream(VirtualMachineImpl vm, Packet pkt) { + this.vm = vm; + this.pkt = pkt; + this.isCommitted = true; /* read only stream */ + } + + int id() { + return pkt.id; + } + + void send() { + if (!isCommitted) { + pkt.data = dataStream.toByteArray(); + vm.sendToTarget(pkt); + isCommitted = true; + } + } + + void waitForReply() throws JDWPException { + if (!isCommitted) { + throw new InternalException("waitForReply without send"); + } + + vm.waitForTargetReply(pkt); + + if (pkt.errorCode != Packet.ReplyNoError) { + throw new JDWPException(pkt.errorCode); + } + } + + void writeBoolean(boolean data) { + if(data) { + dataStream.write( 1 ); + } else { + dataStream.write( 0 ); + } + } + + void writeByte(byte data) { + dataStream.write( data ); + } + + void writeChar(char data) { + dataStream.write( (byte)((data >>> 8) & 0xFF) ); + dataStream.write( (byte)((data >>> 0) & 0xFF) ); + } + + void writeShort(short data) { + dataStream.write( (byte)((data >>> 8) & 0xFF) ); + dataStream.write( (byte)((data >>> 0) & 0xFF) ); + } + + void writeInt(int data) { + dataStream.write( (byte)((data >>> 24) & 0xFF) ); + dataStream.write( (byte)((data >>> 16) & 0xFF) ); + dataStream.write( (byte)((data >>> 8) & 0xFF) ); + dataStream.write( (byte)((data >>> 0) & 0xFF) ); + } + + void writeLong(long data) { + dataStream.write( (byte)((data >>> 56) & 0xFF) ); + dataStream.write( (byte)((data >>> 48) & 0xFF) ); + dataStream.write( (byte)((data >>> 40) & 0xFF) ); + dataStream.write( (byte)((data >>> 32) & 0xFF) ); + + dataStream.write( (byte)((data >>> 24) & 0xFF) ); + dataStream.write( (byte)((data >>> 16) & 0xFF) ); + dataStream.write( (byte)((data >>> 8) & 0xFF) ); + dataStream.write( (byte)((data >>> 0) & 0xFF) ); + } + + void writeFloat(float data) { + writeInt(Float.floatToIntBits(data)); + } + + void writeDouble(double data) { + writeLong(Double.doubleToLongBits(data)); + } + + void writeID(int size, long data) { + switch (size) { + case 8: + writeLong(data); + break; + case 4: + writeInt((int)data); + break; + case 2: + writeShort((short)data); + break; + default: + throw new UnsupportedOperationException("JDWP: ID size not supported: " + size); + } + } + + void writeNullObjectRef() { + writeObjectRef(0); + } + + void writeObjectRef(long data) { + writeID(vm.sizeofObjectRef, data); + } + + void writeClassRef(long data) { + writeID(vm.sizeofClassRef, data); + } + + void writeMethodRef(long data) { + writeID(vm.sizeofMethodRef, data); + } + + void writeFieldRef(long data) { + writeID(vm.sizeofFieldRef, data); + } + + void writeFrameRef(long data) { + writeID(vm.sizeofFrameRef, data); + } + + void writeByteArray(byte[] data) { + dataStream.write(data, 0, data.length); + } + + void writeString(String string) { + try { + byte[] stringBytes = string.getBytes("UTF8"); + writeInt(stringBytes.length); + writeByteArray(stringBytes); + } catch (java.io.UnsupportedEncodingException e) { + throw new InternalException("Cannot convert string to UTF8 bytes"); + } + } + + void writeLocation(Location location) { + ReferenceTypeImpl refType = (ReferenceTypeImpl)location.declaringType(); + byte tag; + if (refType instanceof ClassType) { + tag = JDWP.TypeTag.CLASS; + } else if (refType instanceof InterfaceType) { + // It's possible to have executable code in an interface + tag = JDWP.TypeTag.INTERFACE; + } else { + throw new InternalException("Invalid Location"); + } + writeByte(tag); + writeClassRef(refType.ref()); + writeMethodRef(((MethodImpl)location.method()).ref()); + writeLong(location.codeIndex()); + } + + void writeValue(Value val) { + try { + writeValueChecked(val); + } catch (InvalidTypeException exc) { // should never happen + throw new RuntimeException( + "Internal error: Invalid Tag/Type pair"); + } + } + + void writeValueChecked(Value val) throws InvalidTypeException { + writeByte(ValueImpl.typeValueKey(val)); + writeUntaggedValue(val); + } + + void writeUntaggedValue(Value val) { + try { + writeUntaggedValueChecked(val); + } catch (InvalidTypeException exc) { // should never happen + throw new RuntimeException( + "Internal error: Invalid Tag/Type pair"); + } + } + + void writeUntaggedValueChecked(Value val) throws InvalidTypeException { + byte tag = ValueImpl.typeValueKey(val); + if (isObjectTag(tag)) { + if (val == null) { + writeObjectRef(0); + } else { + if (!(val instanceof ObjectReference)) { + throw new InvalidTypeException(); + } + writeObjectRef(((ObjectReferenceImpl)val).ref()); + } + } else { + switch (tag) { + case JDWP.Tag.BYTE: + if(!(val instanceof ByteValue)) + throw new InvalidTypeException(); + + writeByte(((PrimitiveValue)val).byteValue()); + break; + + case JDWP.Tag.CHAR: + if(!(val instanceof CharValue)) + throw new InvalidTypeException(); + + writeChar(((PrimitiveValue)val).charValue()); + break; + + case JDWP.Tag.FLOAT: + if(!(val instanceof FloatValue)) + throw new InvalidTypeException(); + + writeFloat(((PrimitiveValue)val).floatValue()); + break; + + case JDWP.Tag.DOUBLE: + if(!(val instanceof DoubleValue)) + throw new InvalidTypeException(); + + writeDouble(((PrimitiveValue)val).doubleValue()); + break; + + case JDWP.Tag.INT: + if(!(val instanceof IntegerValue)) + throw new InvalidTypeException(); + + writeInt(((PrimitiveValue)val).intValue()); + break; + + case JDWP.Tag.LONG: + if(!(val instanceof LongValue)) + throw new InvalidTypeException(); + + writeLong(((PrimitiveValue)val).longValue()); + break; + + case JDWP.Tag.SHORT: + if(!(val instanceof ShortValue)) + throw new InvalidTypeException(); + + writeShort(((PrimitiveValue)val).shortValue()); + break; + + case JDWP.Tag.BOOLEAN: + if(!(val instanceof BooleanValue)) + throw new InvalidTypeException(); + + writeBoolean(((PrimitiveValue)val).booleanValue()); + break; + } + } + } + + + + /** + * Read byte represented as one bytes. + */ + byte readByte() { + byte ret = pkt.data[inCursor]; + inCursor += 1; + return ret; + } + + /** + * Read boolean represented as one byte. + */ + boolean readBoolean() { + byte ret = readByte(); + return (ret != 0); + } + + /** + * Read char represented as two bytes. + */ + char readChar() { + int b1, b2; + + b1 = pkt.data[inCursor++] & 0xff; + b2 = pkt.data[inCursor++] & 0xff; + + return (char)((b1 << 8) + b2); + } + + /** + * Read short represented as two bytes. + */ + short readShort() { + int b1, b2; + + b1 = pkt.data[inCursor++] & 0xff; + b2 = pkt.data[inCursor++] & 0xff; + + return (short)((b1 << 8) + b2); + } + + /** + * Read int represented as four bytes. + */ + int readInt() { + int b1,b2,b3,b4; + + b1 = pkt.data[inCursor++] & 0xff; + b2 = pkt.data[inCursor++] & 0xff; + b3 = pkt.data[inCursor++] & 0xff; + b4 = pkt.data[inCursor++] & 0xff; + + return ((b1 << 24) + (b2 << 16) + (b3 << 8) + b4); + } + + /** + * Read long represented as eight bytes. + */ + long readLong() { + long b1,b2,b3,b4; + long b5,b6,b7,b8; + + b1 = pkt.data[inCursor++] & 0xff; + b2 = pkt.data[inCursor++] & 0xff; + b3 = pkt.data[inCursor++] & 0xff; + b4 = pkt.data[inCursor++] & 0xff; + + b5 = pkt.data[inCursor++] & 0xff; + b6 = pkt.data[inCursor++] & 0xff; + b7 = pkt.data[inCursor++] & 0xff; + b8 = pkt.data[inCursor++] & 0xff; + + return ((b1 << 56) + (b2 << 48) + (b3 << 40) + (b4 << 32) + + (b5 << 24) + (b6 << 16) + (b7 << 8) + b8); + } + + /** + * Read float represented as four bytes. + */ + float readFloat() { + return Float.intBitsToFloat(readInt()); + } + + /** + * Read double represented as eight bytes. + */ + double readDouble() { + return Double.longBitsToDouble(readLong()); + } + + /** + * Read string represented as four byte length followed by + * characters of the string. + */ + String readString() { + String ret; + int len = readInt(); + + try { + ret = new String(pkt.data, inCursor, len, "UTF8"); + } catch(java.io.UnsupportedEncodingException e) { + System.err.println(e); + ret = "Conversion error!"; + } + inCursor += len; + return ret; + } + + private long readID(int size) { + switch (size) { + case 8: + return readLong(); + case 4: + return (long)readInt(); + case 2: + return (long)readShort(); + default: + throw new UnsupportedOperationException("JDWP: ID size not supported: " + size); + } + } + + /** + * Read object represented as vm specific byte sequence. + */ + long readObjectRef() { + return readID(vm.sizeofObjectRef); + } + + long readClassRef() { + return readID(vm.sizeofClassRef); + } + + ObjectReferenceImpl readTaggedObjectReference() { + byte typeKey = readByte(); + return vm.objectMirror(readObjectRef(), typeKey); + } + + ObjectReferenceImpl readObjectReference() { + return vm.objectMirror(readObjectRef()); + } + + StringReferenceImpl readStringReference() { + long ref = readObjectRef(); + return vm.stringMirror(ref); + } + + ArrayReferenceImpl readArrayReference() { + long ref = readObjectRef(); + return vm.arrayMirror(ref); + } + + ThreadReferenceImpl readThreadReference() { + long ref = readObjectRef(); + return vm.threadMirror(ref); + } + + ThreadGroupReferenceImpl readThreadGroupReference() { + long ref = readObjectRef(); + return vm.threadGroupMirror(ref); + } + + ClassLoaderReferenceImpl readClassLoaderReference() { + long ref = readObjectRef(); + return vm.classLoaderMirror(ref); + } + + ClassObjectReferenceImpl readClassObjectReference() { + long ref = readObjectRef(); + return vm.classObjectMirror(ref); + } + + ReferenceTypeImpl readReferenceType() { + byte tag = readByte(); + long ref = readObjectRef(); + return vm.referenceType(ref, tag); + } + + /** + * Read method reference represented as vm specific byte sequence. + */ + long readMethodRef() { + return readID(vm.sizeofMethodRef); + } + + /** + * Read field reference represented as vm specific byte sequence. + */ + long readFieldRef() { + return readID(vm.sizeofFieldRef); + } + + /** + * Read field represented as vm specific byte sequence. + */ + Field readField() { + ReferenceTypeImpl refType = (ReferenceTypeImpl)readReferenceType(); + long fieldRef = readFieldRef(); + return refType.getFieldMirror(fieldRef); + } + + /** + * Read frame represented as vm specific byte sequence. + */ + long readFrameRef() { + return readID(vm.sizeofFrameRef); + } + + /** + * Read a value, first byte describes type of value to read. + */ + ValueImpl readValue() { + byte typeKey = readByte(); + return readUntaggedValue(typeKey); + } + + ValueImpl readUntaggedValue(byte typeKey) { + ValueImpl val = null; + + if (isObjectTag(typeKey)) { + val = vm.objectMirror(readObjectRef(), typeKey); + } else { + switch(typeKey) { + case JDWP.Tag.BYTE: + val = new ByteValueImpl(vm, readByte()); + break; + + case JDWP.Tag.CHAR: + val = new CharValueImpl(vm, readChar()); + break; + + case JDWP.Tag.FLOAT: + val = new FloatValueImpl(vm, readFloat()); + break; + + case JDWP.Tag.DOUBLE: + val = new DoubleValueImpl(vm, readDouble()); + break; + + case JDWP.Tag.INT: + val = new IntegerValueImpl(vm, readInt()); + break; + + case JDWP.Tag.LONG: + val = new LongValueImpl(vm, readLong()); + break; + + case JDWP.Tag.SHORT: + val = new ShortValueImpl(vm, readShort()); + break; + + case JDWP.Tag.BOOLEAN: + val = new BooleanValueImpl(vm, readBoolean()); + break; + + case JDWP.Tag.VOID: + val = new VoidValueImpl(vm); + break; + } + } + return val; + } + + /** + * Read location represented as vm specific byte sequence. + */ + Location readLocation() { + byte tag = readByte(); + long classRef = readObjectRef(); + long methodRef = readMethodRef(); + long codeIndex = readLong(); + if (classRef != 0) { + /* Valid location */ + ReferenceTypeImpl refType = vm.referenceType(classRef, tag); + return new LocationImpl(vm, refType, methodRef, codeIndex); + } else { + /* Null location (example: uncaught exception) */ + return null; + } + } + + byte[] readByteArray(int length) { + byte[] array = new byte[length]; + System.arraycopy(pkt.data, inCursor, array, 0, length); + inCursor += length; + return array; + } + + List readArrayRegion() { + byte typeKey = readByte(); + int length = readInt(); + List list = new ArrayList(length); + boolean gettingObjects = isObjectTag(typeKey); + for (int i = 0; i < length; i++) { + /* + * Each object comes back with a type key which might + * identify a more specific type than the type key we + * passed in, so we use it in the decodeValue call. + * (For primitives, we just use the original one) + */ + if (gettingObjects) { + typeKey = readByte(); + } + Value value = readUntaggedValue(typeKey); + list.add(value); + } + + return list; + } + + void writeArrayRegion(List srcValues) { + writeInt(srcValues.size()); + for (int i = 0; i < srcValues.size(); i++) { + Value value = srcValues.get(i); + writeUntaggedValue(value); + } + } + + int skipBytes(int n) { + inCursor += n; + return n; + } + + byte command() { + return (byte)pkt.cmd; + } + + static boolean isObjectTag(byte tag) { + return (tag == JDWP.Tag.OBJECT) || + (tag == JDWP.Tag.ARRAY) || + (tag == JDWP.Tag.STRING) || + (tag == JDWP.Tag.THREAD) || + (tag == JDWP.Tag.THREAD_GROUP) || + (tag == JDWP.Tag.CLASS_LOADER) || + (tag == JDWP.Tag.CLASS_OBJECT); + } +}