jdk/src/share/back/inStream.c
changeset 2 90ce3da70b43
child 1090 c5805b1672a6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/back/inStream.c	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,490 @@
+/*
+ * Copyright 1998-2006 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.
+ */
+
+#include "util.h"
+#include "stream.h"
+#include "inStream.h"
+#include "transport.h"
+#include "bag.h"
+#include "commonRef.h"
+#include "FrameID.h"
+#include "typedefs.h"
+
+#define INITIAL_REF_ALLOC 50
+#define SMALLEST(a, b) ((a) < (b)) ? (a) : (b)
+
+/*
+ * TO DO: Support processing of replies through command input streams.
+ */
+void
+inStream_init(PacketInputStream *stream, jdwpPacket packet)
+{
+    stream->packet = packet;
+    stream->error = JDWP_ERROR(NONE);
+    stream->left = packet.type.cmd.len;
+    stream->current = packet.type.cmd.data;
+    stream->refs = bagCreateBag(sizeof(jobject), INITIAL_REF_ALLOC);
+    if (stream->refs == NULL) {
+        stream->error = JDWP_ERROR(OUT_OF_MEMORY);
+    }
+}
+
+jint
+inStream_id(PacketInputStream *stream)
+{
+    return stream->packet.type.cmd.id;
+}
+
+jbyte
+inStream_command(PacketInputStream *stream)
+{
+    return stream->packet.type.cmd.cmd;
+}
+
+static jdwpError
+readBytes(PacketInputStream *stream, void *dest, int size)
+{
+    if (stream->error) {
+        return stream->error;
+    }
+
+    if (size > stream->left) {
+        stream->error = JDWP_ERROR(INTERNAL);
+        return stream->error;
+    }
+
+    if (dest) {
+        (void)memcpy(dest, stream->current, size);
+    }
+    stream->current += size;
+    stream->left -= size;
+
+    return stream->error;
+}
+
+jdwpError
+inStream_skipBytes(PacketInputStream *stream, jint size) {
+    return readBytes(stream, NULL, size);
+}
+
+jboolean
+inStream_readBoolean(PacketInputStream *stream)
+{
+    jbyte flag = 0;
+    (void)readBytes(stream, &flag, sizeof(flag));
+    if (stream->error) {
+        return 0;
+    } else {
+        return flag ? JNI_TRUE : JNI_FALSE;
+    }
+}
+
+jbyte
+inStream_readByte(PacketInputStream *stream)
+{
+    jbyte val = 0;
+    (void)readBytes(stream, &val, sizeof(val));
+    return val;
+}
+
+jbyte *
+inStream_readBytes(PacketInputStream *stream, int length, jbyte *buf)
+{
+    (void)readBytes(stream, buf, length);
+    return buf;
+}
+
+jchar
+inStream_readChar(PacketInputStream *stream)
+{
+    jchar val = 0;
+    (void)readBytes(stream, &val, sizeof(val));
+    return JAVA_TO_HOST_CHAR(val);
+}
+
+jshort
+inStream_readShort(PacketInputStream *stream)
+{
+    jshort val = 0;
+    (void)readBytes(stream, &val, sizeof(val));
+    return JAVA_TO_HOST_SHORT(val);
+}
+
+jint
+inStream_readInt(PacketInputStream *stream)
+{
+    jint val = 0;
+    (void)readBytes(stream, &val, sizeof(val));
+    return JAVA_TO_HOST_INT(val);
+}
+
+jlong
+inStream_readLong(PacketInputStream *stream)
+{
+    jlong val = 0;
+    (void)readBytes(stream, &val, sizeof(val));
+    return JAVA_TO_HOST_LONG(val);
+}
+
+jfloat
+inStream_readFloat(PacketInputStream *stream)
+{
+    jfloat val = 0;
+    (void)readBytes(stream, &val, sizeof(val));
+    return JAVA_TO_HOST_FLOAT(val);
+}
+
+jdouble
+inStream_readDouble(PacketInputStream *stream)
+{
+    jdouble val = 0;
+    (void)readBytes(stream, &val, sizeof(val));
+    return JAVA_TO_HOST_DOUBLE(val);
+}
+
+/*
+ * Read an object from the stream. The ID used in the wire protocol
+ * is converted to a reference which is returned. The reference is
+ * global and strong, but it should *not* be deleted by the caller
+ * since it is freed when this stream is destroyed.
+ */
+jobject
+inStream_readObjectRef(JNIEnv *env, PacketInputStream *stream)
+{
+    jobject ref;
+    jobject *refPtr;
+    jlong id = inStream_readLong(stream);
+    if (stream->error) {
+        return NULL;
+    }
+    if (id == NULL_OBJECT_ID) {
+        return NULL;
+    }
+
+    ref = commonRef_idToRef(env, id);
+    if (ref == NULL) {
+        stream->error = JDWP_ERROR(INVALID_OBJECT);
+        return NULL;
+    }
+
+    refPtr = bagAdd(stream->refs);
+    if (refPtr == NULL) {
+        commonRef_idToRef_delete(env, ref);
+        return NULL;
+    }
+
+    *refPtr = ref;
+    return ref;
+}
+
+/*
+ * Read a raw object id from the stream. This should be used rarely.
+ * Normally, inStream_readObjectRef is preferred since it takes care
+ * of reference conversion and tracking. Only code that needs to
+ * perform maintence of the commonRef hash table uses this function.
+ */
+jlong
+inStream_readObjectID(PacketInputStream *stream)
+{
+    return inStream_readLong(stream);
+}
+
+jclass
+inStream_readClassRef(JNIEnv *env, PacketInputStream *stream)
+{
+    jobject object = inStream_readObjectRef(env, stream);
+    if (object == NULL) {
+        /*
+         * Could be error or just the null reference. In either case,
+         * stop now.
+         */
+        return NULL;
+    }
+    if (!isClass(object)) {
+        stream->error = JDWP_ERROR(INVALID_CLASS);
+        return NULL;
+    }
+    return object;
+}
+
+jthread
+inStream_readThreadRef(JNIEnv *env, PacketInputStream *stream)
+{
+    jobject object = inStream_readObjectRef(env, stream);
+    if (object == NULL) {
+        /*
+         * Could be error or just the null reference. In either case,
+         * stop now.
+         */
+        return NULL;
+    }
+    if (!isThread(object)) {
+        stream->error = JDWP_ERROR(INVALID_THREAD);
+        return NULL;
+    }
+    return object;
+}
+
+jthreadGroup
+inStream_readThreadGroupRef(JNIEnv *env, PacketInputStream *stream)
+{
+    jobject object = inStream_readObjectRef(env, stream);
+    if (object == NULL) {
+        /*
+         * Could be error or just the null reference. In either case,
+         * stop now.
+         */
+        return NULL;
+    }
+    if (!isThreadGroup(object)) {
+        stream->error = JDWP_ERROR(INVALID_THREAD_GROUP);
+        return NULL;
+    }
+    return object;
+}
+
+jstring
+inStream_readStringRef(JNIEnv *env, PacketInputStream *stream)
+{
+    jobject object = inStream_readObjectRef(env, stream);
+    if (object == NULL) {
+        /*
+         * Could be error or just the null reference. In either case,
+         * stop now.
+         */
+        return NULL;
+    }
+    if (!isString(object)) {
+        stream->error = JDWP_ERROR(INVALID_STRING);
+        return NULL;
+    }
+    return object;
+}
+
+jclass
+inStream_readClassLoaderRef(JNIEnv *env, PacketInputStream *stream)
+{
+    jobject object = inStream_readObjectRef(env, stream);
+    if (object == NULL) {
+        /*
+         * Could be error or just the null reference. In either case,
+         * stop now.
+         */
+        return NULL;
+    }
+    if (!isClassLoader(object)) {
+        stream->error = JDWP_ERROR(INVALID_CLASS_LOADER);
+        return NULL;
+    }
+    return object;
+}
+
+jarray
+inStream_readArrayRef(JNIEnv *env, PacketInputStream *stream)
+{
+    jobject object = inStream_readObjectRef(env, stream);
+    if (object == NULL) {
+        /*
+         * Could be error or just the null reference. In either case,
+         * stop now.
+         */
+        return NULL;
+    }
+    if (!isArray(object)) {
+        stream->error = JDWP_ERROR(INVALID_ARRAY);
+        return NULL;
+    }
+    return object;
+}
+
+/*
+ * Next 3 functions read an Int and convert to a Pointer!?
+ * If sizeof(jxxxID) == 8 we must read these values as Longs.
+ */
+FrameID
+inStream_readFrameID(PacketInputStream *stream)
+{
+    if (sizeof(FrameID) == 8) {
+        /*LINTED*/
+        return (FrameID)inStream_readLong(stream);
+    } else {
+        /*LINTED*/
+        return (FrameID)inStream_readInt(stream);
+    }
+}
+
+jmethodID
+inStream_readMethodID(PacketInputStream *stream)
+{
+    if (sizeof(jmethodID) == 8) {
+        /*LINTED*/
+        return (jmethodID)(intptr_t)inStream_readLong(stream);
+    } else {
+        /*LINTED*/
+        return (jmethodID)(intptr_t)inStream_readInt(stream);
+    }
+}
+
+jfieldID
+inStream_readFieldID(PacketInputStream *stream)
+{
+    if (sizeof(jfieldID) == 8) {
+        /*LINTED*/
+        return (jfieldID)(intptr_t)inStream_readLong(stream);
+    } else {
+        /*LINTED*/
+        return (jfieldID)(intptr_t)inStream_readInt(stream);
+    }
+}
+
+jlocation
+inStream_readLocation(PacketInputStream *stream)
+{
+    return (jlocation)inStream_readLong(stream);
+}
+
+char *
+inStream_readString(PacketInputStream *stream)
+{
+    int length;
+    char *string;
+
+    length = inStream_readInt(stream);
+    string = jvmtiAllocate(length + 1);
+    if (string != NULL) {
+        int new_length;
+
+        (void)readBytes(stream, string, length);
+        string[length] = '\0';
+
+        /* This is Standard UTF-8, convert to Modified UTF-8 if necessary */
+        new_length = (gdata->npt->utf8sToUtf8mLength)
+                             (gdata->npt->utf, (jbyte*)string, length);
+        if ( new_length != length ) {
+            char *new_string;
+
+            new_string = jvmtiAllocate(new_length+1);
+            (gdata->npt->utf8sToUtf8m)
+                             (gdata->npt->utf, (jbyte*)string, length,
+                              (jbyte*)new_string, new_length);
+            jvmtiDeallocate(string);
+            return new_string;
+        }
+    }
+    return string;
+}
+
+jboolean
+inStream_endOfInput(PacketInputStream *stream)
+{
+    return (stream->left > 0);
+}
+
+jdwpError
+inStream_error(PacketInputStream *stream)
+{
+    return stream->error;
+}
+
+void
+inStream_clearError(PacketInputStream *stream) {
+    stream->error = JDWP_ERROR(NONE);
+}
+
+jvalue
+inStream_readValue(PacketInputStream *stream, jbyte *typeKeyPtr)
+{
+    jvalue value;
+    jbyte typeKey = inStream_readByte(stream);
+    if (stream->error) {
+        value.j = 0L;
+        return value;
+    }
+
+    if (isObjectTag(typeKey)) {
+        value.l = inStream_readObjectRef(getEnv(), stream);
+    } else {
+        switch (typeKey) {
+            case JDWP_TAG(BYTE):
+                value.b = inStream_readByte(stream);
+                break;
+
+            case JDWP_TAG(CHAR):
+                value.c = inStream_readChar(stream);
+                break;
+
+            case JDWP_TAG(FLOAT):
+                value.f = inStream_readFloat(stream);
+                break;
+
+            case JDWP_TAG(DOUBLE):
+                value.d = inStream_readDouble(stream);
+                break;
+
+            case JDWP_TAG(INT):
+                value.i = inStream_readInt(stream);
+                break;
+
+            case JDWP_TAG(LONG):
+                value.j = inStream_readLong(stream);
+                break;
+
+            case JDWP_TAG(SHORT):
+                value.s = inStream_readShort(stream);
+                break;
+
+            case JDWP_TAG(BOOLEAN):
+                value.z = inStream_readBoolean(stream);
+                break;
+            default:
+                stream->error = JDWP_ERROR(INVALID_TAG);
+                break;
+        }
+    }
+    if (typeKeyPtr) {
+        *typeKeyPtr = typeKey;
+    }
+    return value;
+}
+
+static jboolean
+deleteRef(void *elementPtr, void *arg)
+{
+    JNIEnv *env = arg;
+    jobject *refPtr = elementPtr;
+    commonRef_idToRef_delete(env, *refPtr);
+    return JNI_TRUE;
+}
+
+void
+inStream_destroy(PacketInputStream *stream)
+{
+    if (stream->packet.type.cmd.data != NULL) {
+    jvmtiDeallocate(stream->packet.type.cmd.data);
+    }
+
+    (void)bagEnumerateOver(stream->refs, deleteRef, (void *)getEnv());
+    bagDestroyBag(stream->refs);
+}