source: trunk/openjdk/jdk/src/share/back/outStream.c

Last change on this file was 278, checked in by dmik, 14 years ago

trunk: Merged in openjdk6 b22 from branches/vendor/oracle.

File size: 13.6 KB
Line 
1/*
2 * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include "util.h"
27#include "stream.h"
28#include "outStream.h"
29#include "inStream.h"
30#include "transport.h"
31#include "commonRef.h"
32#include "bag.h"
33#include "FrameID.h"
34
35#define INITIAL_ID_ALLOC 50
36#define SMALLEST(a, b) ((a) < (b)) ? (a) : (b)
37
38static void
39commonInit(PacketOutputStream *stream)
40{
41 stream->current = &stream->initialSegment[0];
42 stream->left = sizeof(stream->initialSegment);
43 stream->segment = &stream->firstSegment;
44 stream->segment->length = 0;
45 stream->segment->data = &stream->initialSegment[0];
46 stream->segment->next = NULL;
47 stream->error = JDWP_ERROR(NONE);
48 stream->sent = JNI_FALSE;
49 stream->ids = bagCreateBag(sizeof(jlong), INITIAL_ID_ALLOC);
50 if (stream->ids == NULL) {
51 stream->error = JDWP_ERROR(OUT_OF_MEMORY);
52 }
53}
54
55void
56outStream_initCommand(PacketOutputStream *stream, jint id,
57 jbyte flags, jbyte commandSet, jbyte command)
58{
59 commonInit(stream);
60
61 /*
62 * Command-specific initialization
63 */
64 stream->packet.type.cmd.id = id;
65 stream->packet.type.cmd.cmdSet = commandSet;
66 stream->packet.type.cmd.cmd = command;
67
68 stream->packet.type.cmd.flags = flags;
69}
70
71void
72outStream_initReply(PacketOutputStream *stream, jint id)
73{
74 commonInit(stream);
75
76 /*
77 * Reply-specific initialization
78 */
79 stream->packet.type.reply.id = id;
80 stream->packet.type.reply.errorCode = 0x0;
81 stream->packet.type.cmd.flags = (jbyte)JDWPTRANSPORT_FLAGS_REPLY;
82}
83
84jint
85outStream_id(PacketOutputStream *stream)
86{
87 return stream->packet.type.cmd.id;
88}
89
90jbyte
91outStream_command(PacketOutputStream *stream)
92{
93 /* Only makes sense for commands */
94 JDI_ASSERT(!(stream->packet.type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY));
95 return stream->packet.type.cmd.cmd;
96}
97
98static jdwpError
99writeBytes(PacketOutputStream *stream, void *source, int size)
100{
101 jbyte *bytes = (jbyte *)source;
102
103 if (stream->error) {
104 return stream->error;
105 }
106 while (size > 0) {
107 jint count;
108 if (stream->left == 0) {
109 jint segSize = SMALLEST(2 * stream->segment->length, MAX_SEGMENT_SIZE);
110 jbyte *newSeg = jvmtiAllocate(segSize);
111 struct PacketData *newHeader = jvmtiAllocate(sizeof(*newHeader));
112 if ((newSeg == NULL) || (newHeader == NULL)) {
113 jvmtiDeallocate(newSeg);
114 jvmtiDeallocate(newHeader);
115 stream->error = JDWP_ERROR(OUT_OF_MEMORY);
116 return stream->error;
117 }
118 newHeader->length = 0;
119 newHeader->data = newSeg;
120 newHeader->next = NULL;
121 stream->segment->next = newHeader;
122 stream->segment = newHeader;
123 stream->current = newHeader->data;
124 stream->left = segSize;
125 }
126 count = SMALLEST(size, stream->left);
127 (void)memcpy(stream->current, bytes, count);
128 stream->current += count;
129 stream->left -= count;
130 stream->segment->length += count;
131 size -= count;
132 bytes += count;
133 }
134 return JDWP_ERROR(NONE);
135}
136
137jdwpError
138outStream_writeBoolean(PacketOutputStream *stream, jboolean val)
139{
140 jbyte byte = (val != 0) ? 1 : 0;
141 return writeBytes(stream, &byte, sizeof(byte));
142}
143
144jdwpError
145outStream_writeByte(PacketOutputStream *stream, jbyte val)
146{
147 return writeBytes(stream, &val, sizeof(val));
148}
149
150jdwpError
151outStream_writeChar(PacketOutputStream *stream, jchar val)
152{
153 val = HOST_TO_JAVA_CHAR(val);
154 return writeBytes(stream, &val, sizeof(val));
155}
156
157jdwpError
158outStream_writeShort(PacketOutputStream *stream, jshort val)
159{
160 val = HOST_TO_JAVA_SHORT(val);
161 return writeBytes(stream, &val, sizeof(val));
162}
163
164jdwpError
165outStream_writeInt(PacketOutputStream *stream, jint val)
166{
167 val = HOST_TO_JAVA_INT(val);
168 return writeBytes(stream, &val, sizeof(val));
169}
170
171jdwpError
172outStream_writeLong(PacketOutputStream *stream, jlong val)
173{
174 val = HOST_TO_JAVA_LONG(val);
175 return writeBytes(stream, &val, sizeof(val));
176}
177
178jdwpError
179outStream_writeFloat(PacketOutputStream *stream, jfloat val)
180{
181 val = HOST_TO_JAVA_FLOAT(val);
182 return writeBytes(stream, &val, sizeof(val));
183}
184
185jdwpError
186outStream_writeDouble(PacketOutputStream *stream, jdouble val)
187{
188 val = HOST_TO_JAVA_DOUBLE(val);
189 return writeBytes(stream, &val, sizeof(val));
190}
191
192jdwpError
193outStream_writeObjectTag(JNIEnv *env, PacketOutputStream *stream, jobject val)
194{
195 return outStream_writeByte(stream, specificTypeKey(env, val));
196}
197
198jdwpError
199outStream_writeObjectRef(JNIEnv *env, PacketOutputStream *stream, jobject val)
200{
201 jlong id;
202 jlong *idPtr;
203
204 if (stream->error) {
205 return stream->error;
206 }
207
208 if (val == NULL) {
209 id = NULL_OBJECT_ID;
210 } else {
211 /* Convert the object to an object id */
212 id = commonRef_refToID(env, val);
213 if (id == NULL_OBJECT_ID) {
214 stream->error = JDWP_ERROR(OUT_OF_MEMORY);
215 return stream->error;
216 }
217
218 /* Track the common ref in case we need to release it on a future error */
219 idPtr = bagAdd(stream->ids);
220 if (idPtr == NULL) {
221 commonRef_release(env, id);
222 stream->error = JDWP_ERROR(OUT_OF_MEMORY);
223 return stream->error;
224 } else {
225 *idPtr = id;
226 }
227
228 /* Add the encoded object id to the stream */
229 id = HOST_TO_JAVA_LONG(id);
230 }
231
232 return writeBytes(stream, &id, sizeof(id));
233}
234
235jdwpError
236outStream_writeFrameID(PacketOutputStream *stream, FrameID val)
237{
238 /*
239 * Not good - we're writing a pointer as a jint. Need
240 * to write as a jlong if sizeof(FrameID) == 8.
241 */
242 if (sizeof(FrameID) == 8) {
243 /*LINTED*/
244 return outStream_writeLong(stream, (jlong)val);
245 } else {
246 /*LINTED*/
247 return outStream_writeInt(stream, (jint)val);
248 }
249}
250
251jdwpError
252outStream_writeMethodID(PacketOutputStream *stream, jmethodID val)
253{
254 /*
255 * Not good - we're writing a pointer as a jint. Need
256 * to write as a jlong if sizeof(jmethodID) == 8.
257 */
258 if (sizeof(jmethodID) == 8) {
259 /*LINTED*/
260 return outStream_writeLong(stream, (jlong)(intptr_t)val);
261 } else {
262 /*LINTED*/
263 return outStream_writeInt(stream, (jint)(intptr_t)val);
264 }
265}
266
267jdwpError
268outStream_writeFieldID(PacketOutputStream *stream, jfieldID val)
269{
270 /*
271 * Not good - we're writing a pointer as a jint. Need
272 * to write as a jlong if sizeof(jfieldID) == 8.
273 */
274 if (sizeof(jfieldID) == 8) {
275 /*LINTED*/
276 return outStream_writeLong(stream, (jlong)(intptr_t)val);
277 } else {
278 /*LINTED*/
279 return outStream_writeInt(stream, (jint)(intptr_t)val);
280 }
281}
282
283jdwpError
284outStream_writeLocation(PacketOutputStream *stream, jlocation val)
285{
286 return outStream_writeLong(stream, (jlong)val);
287}
288
289jdwpError
290outStream_writeByteArray(PacketOutputStream*stream, jint length,
291 jbyte *bytes)
292{
293 (void)outStream_writeInt(stream, length);
294 return writeBytes(stream, bytes, length);
295}
296
297jdwpError
298outStream_writeString(PacketOutputStream *stream, char *string)
299{
300 jdwpError error;
301 jint length;
302
303 /* Options utf8=y/n controls if we want Standard UTF-8 or Modified */
304 if ( gdata->modifiedUtf8 ) {
305 length = (int)strlen(string);
306 (void)outStream_writeInt(stream, length);
307 error = writeBytes(stream, (jbyte *)string, length);
308 } else {
309 jint new_length;
310
311 length = (int)strlen(string);
312 new_length = (gdata->npt->utf8mToUtf8sLength)
313 (gdata->npt->utf, (jbyte*)string, length);
314 if ( new_length == length ) {
315 (void)outStream_writeInt(stream, length);
316 error = writeBytes(stream, (jbyte *)string, length);
317 } else {
318 char *new_string;
319
320 new_string = jvmtiAllocate(new_length+1);
321 (gdata->npt->utf8mToUtf8s)
322 (gdata->npt->utf, (jbyte*)string, length,
323 (jbyte*)new_string, new_length);
324 (void)outStream_writeInt(stream, new_length);
325 error = writeBytes(stream, (jbyte *)new_string, new_length);
326 jvmtiDeallocate(new_string);
327 }
328 }
329 return error;
330}
331
332jdwpError
333outStream_writeValue(JNIEnv *env, PacketOutputStream *out,
334 jbyte typeKey, jvalue value)
335{
336 if (typeKey == JDWP_TAG(OBJECT)) {
337 (void)outStream_writeByte(out, specificTypeKey(env, value.l));
338 } else {
339 (void)outStream_writeByte(out, typeKey);
340 }
341 if (isObjectTag(typeKey)) {
342 (void)outStream_writeObjectRef(env, out, value.l);
343 } else {
344 switch (typeKey) {
345 case JDWP_TAG(BYTE):
346 return outStream_writeByte(out, value.b);
347
348 case JDWP_TAG(CHAR):
349 return outStream_writeChar(out, value.c);
350
351 case JDWP_TAG(FLOAT):
352 return outStream_writeFloat(out, value.f);
353
354 case JDWP_TAG(DOUBLE):
355 return outStream_writeDouble(out, value.d);
356
357 case JDWP_TAG(INT):
358 return outStream_writeInt(out, value.i);
359
360 case JDWP_TAG(LONG):
361 return outStream_writeLong(out, value.j);
362
363 case JDWP_TAG(SHORT):
364 return outStream_writeShort(out, value.s);
365
366 case JDWP_TAG(BOOLEAN):
367 return outStream_writeBoolean(out, value.z);
368
369 case JDWP_TAG(VOID): /* happens with function return values */
370 /* write nothing */
371 return JDWP_ERROR(NONE);
372
373 default:
374 EXIT_ERROR(AGENT_ERROR_INVALID_OBJECT,"Invalid type key");
375 break;
376 }
377 }
378 return JDWP_ERROR(NONE);
379}
380
381jdwpError
382outStream_skipBytes(PacketOutputStream *stream, jint count)
383{
384 int i;
385 for (i = 0; i < count; i++) {
386 (void)outStream_writeByte(stream, 0);
387 }
388 return stream->error;
389}
390
391jdwpError
392outStream_error(PacketOutputStream *stream)
393{
394 return stream->error;
395}
396
397void
398outStream_setError(PacketOutputStream *stream, jdwpError error)
399{
400 if (stream->error == JDWP_ERROR(NONE)) {
401 stream->error = error;
402 LOG_MISC(("outStream_setError error=%s(%d)", jdwpErrorText(error), error));
403 }
404}
405
406static jint
407outStream_send(PacketOutputStream *stream) {
408
409 jint rc;
410 jint len = 0;
411 PacketData *segment;
412 jbyte *data, *posP;
413
414 /*
415 * If there's only 1 segment then we just send the
416 * packet.
417 */
418 if (stream->firstSegment.next == NULL) {
419 stream->packet.type.cmd.len = 11 + stream->firstSegment.length;
420 stream->packet.type.cmd.data = stream->firstSegment.data;
421 rc = transport_sendPacket(&stream->packet);
422 return rc;
423 }
424
425 /*
426 * Multiple segments
427 */
428 len = 0;
429 segment = (PacketData *)&(stream->firstSegment);
430 do {
431 len += segment->length;
432 segment = segment->next;
433 } while (segment != NULL);
434
435 data = jvmtiAllocate(len);
436 if (data == NULL) {
437 return JDWP_ERROR(OUT_OF_MEMORY);
438 }
439
440 posP = data;
441 segment = (PacketData *)&(stream->firstSegment);
442 while (segment != NULL) {
443 (void)memcpy(posP, segment->data, segment->length);
444 posP += segment->length;
445 segment = segment->next;
446 }
447
448 stream->packet.type.cmd.len = 11 + len;
449 stream->packet.type.cmd.data = data;
450 rc = transport_sendPacket(&stream->packet);
451 stream->packet.type.cmd.data = NULL;
452 jvmtiDeallocate(data);
453
454 return rc;
455}
456
457void
458outStream_sendReply(PacketOutputStream *stream)
459{
460 jint rc;
461 if (stream->error) {
462 /*
463 * Don't send any collected stream data on an error reply
464 */
465 stream->packet.type.reply.len = 0;
466 stream->packet.type.reply.errorCode = (jshort)stream->error;
467 }
468 rc = outStream_send(stream);
469 if (rc == 0) {
470 stream->sent = JNI_TRUE;
471 }
472}
473
474void
475outStream_sendCommand(PacketOutputStream *stream)
476{
477 jint rc;
478 if (!stream->error) {
479 rc = outStream_send(stream);
480 if (rc == 0) {
481 stream->sent = JNI_TRUE;
482 }
483 }
484}
485
486
487static jboolean
488releaseID(void *elementPtr, void *arg)
489{
490 jlong *idPtr = elementPtr;
491 commonRef_release(getEnv(), *idPtr);
492 return JNI_TRUE;
493}
494
495void
496outStream_destroy(PacketOutputStream *stream)
497{
498 struct PacketData *next;
499
500 if (stream->error || !stream->sent) {
501 (void)bagEnumerateOver(stream->ids, releaseID, NULL);
502 }
503
504 next = stream->firstSegment.next;
505 while (next != NULL) {
506 struct PacketData *p = next;
507 next = p->next;
508 jvmtiDeallocate(p->data);
509 jvmtiDeallocate(p);
510 }
511 bagDestroyBag(stream->ids);
512}
Note: See TracBrowser for help on using the repository browser.