001 /*
002 * This file is part of the Tuning Fork Visualization Platform
003 * (http://sourceforge.net/projects/tuningforkvp)
004 *
005 * Copyright (c) 2005 - 2008 IBM Corporation.
006 * All rights reserved. This program and the accompanying materials
007 * are made available under the terms of the Eclipse Public License v1.0
008 * which accompanies this distribution, and is available at
009 * http://www.eclipse.org/legal/epl-v10.html
010 *
011 * Contributors:
012 * IBM Corporation - initial API and implementation
013 */
014
015 package com.ibm.tuningfork.tracegen.chunk;
016
017 import java.io.IOException;
018 import java.io.OutputStream;
019
020 import org.jikesrvm.VM;
021 import org.jikesrvm.runtime.Magic;
022 import org.vmmagic.pragma.Inline;
023 import org.vmmagic.pragma.Interruptible;
024 import org.vmmagic.pragma.Uninterruptible;
025
026 /*
027 * There are 3 basic operations: (1) Closing a chunk which involves fixing up
028 * data that cannot be determined initially such as the length field. Subclasses
029 * should override this at each level and call the superclass's close(). The
030 * base implementation will limit and reset the buffer position so overrides
031 * need to put the position at the end of data. (2) Writing the data out. This
032 * method is not overrideable as it simply means to write out the contents of
033 * the buffer. The cursor position will be reset to zero. The entire chunk is
034 * written out and the position is undefined on return. (3) Reset which allows
035 * the buffer object to be reused. Subclasses that can actually be reset should
036 * define a reset method and use the resetImpl method here.
037 */
038 @Uninterruptible
039 public abstract class RawChunk {
040
041 public final static int ENCODING_SPACE_INT = 4;
042 public final static int ENCODING_SPACE_LONG = 8;
043 public final static int ENCODING_SPACE_DOUBLE = 8;
044
045 private final byte[] data;
046 private int cursor = 0;
047 private boolean open = true;
048
049 protected RawChunk(byte[] buffer) {
050 data = buffer;
051 }
052
053 protected RawChunk(int capacity) {
054 this(new byte[capacity]);
055 }
056
057 public void close() {
058 if (!open) {
059 VM.sysWriteln("RawChunk: Cannot close a closed chunk.");
060 }
061 open = false;
062 }
063
064 /* Synchronous */
065 @Interruptible
066 public final void write(OutputStream outputStream) throws IOException {
067 outputStream.write(data, 0, cursor);
068 }
069
070 protected void resetImpl() {
071 cursor = 0;
072 open = true;
073 }
074
075 protected int getPosition() {
076 return cursor;
077 }
078
079 protected void seek(int pos) {
080 cursor = pos;
081 }
082
083 protected final boolean hasRoom(int bytes) {
084 int remaining = data.length - cursor;
085 return remaining >= bytes;
086 }
087
088 protected final boolean addLong(long l) {
089 if (!hasRoom(ENCODING_SPACE_LONG)) {
090 return false;
091 }
092 putLong(l);
093 return true;
094 }
095
096 protected final void addLongUnchecked(long l) {
097 putLong(l);
098 }
099
100 protected final boolean addDouble(double d) {
101 if (!hasRoom(ENCODING_SPACE_DOUBLE)) {
102 return false;
103 }
104 putLong(Magic.doubleAsLongBits(d));
105 return true;
106 }
107
108 protected final void addDoubleUnchecked(double d) {
109 putLong(Magic.doubleAsLongBits(d));
110 }
111
112 protected final boolean addInt(int i) {
113 if (!hasRoom(ENCODING_SPACE_INT)) {
114 return false;
115 }
116 putInt(i);
117 return true;
118 }
119
120 protected final void addIntUnchecked(int i) {
121 putInt(i);
122 }
123
124 protected final boolean addByte(byte b) {
125 if (!hasRoom(1)) {
126 return false;
127 }
128 data[cursor++] = b;
129 return true;
130 }
131
132 protected final boolean addString(String str) {
133 int strLen = JikesRVMSupport.getStringLength(str);
134 int minimalSize = ENCODING_SPACE_INT + strLen;
135 if (!hasRoom(minimalSize)) {
136 return false;
137 }
138 char[] backingChars = JikesRVMSupport.getBackingCharArray(str);
139 return addStringInternal(backingChars);
140 }
141
142 /*
143 * Write String's char[] encoded as UTF-8.
144 * Table from http://tools.ietf.org/html/rfc3629
145 *
146 * Char. number range | UTF-8 octet sequence
147 * (hexadecimal) | (binary)
148 * --------------------+---------------------------------------------
149 * 0000 0000-0000 007F | 0xxxxxxx
150 * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
151 * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
152 * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
153 */
154 protected boolean addStringInternal(char[] backingChars) {
155 int startCursor = cursor;
156 int strLen = backingChars.length;
157 cursor += ENCODING_SPACE_INT;
158
159 for (int i=0; i<strLen; i++) {
160 char c = backingChars[i];
161 if (c <= 0x7f) {
162 data[cursor++] = (byte)(c);
163 } else if (c <= 0x7ff) {
164 if (!hasRoom(1 + (strLen-i))) {
165 cursor = startCursor;
166 return false;
167 }
168 data[cursor++] = (byte)(0xc0 | (c >> 6));
169 data[cursor++] = (byte)(0x80 | (c & 0x3f));
170 } else {
171 if (!hasRoom(2 + (strLen-i))) {
172 cursor = startCursor;
173 return false;
174 }
175 data[cursor++] = (byte)(0xe0 | (c >> 12));
176 data[cursor++] = (byte)(0x80 | ((c & 0xfc0) >> 6));
177 data[cursor++] = (byte)(0x80 | (c & 0x3f));
178 }
179 }
180 int endCursor = cursor;
181 int finalLen = endCursor-startCursor-ENCODING_SPACE_INT;
182 cursor = startCursor;
183 putInt(finalLen);
184 cursor = endCursor;
185 return true;
186 }
187
188 @Inline(value=Inline.When.AllArgumentsAreConstant)
189 private void putLong(long value) {
190 data[cursor + 0] = (byte) ((value >> 56) & 0xff);
191 data[cursor + 1] = (byte) ((value >> 48) & 0xff);
192 data[cursor + 2] = (byte) ((value >> 40) & 0xff);
193 data[cursor + 3] = (byte) ((value >> 32) & 0xff);
194 data[cursor + 4] = (byte) ((value >> 24) & 0xff);
195 data[cursor + 5] = (byte) ((value >> 16) & 0xff);
196 data[cursor + 6] = (byte) ((value >> 8) & 0xff);
197 data[cursor + 7] = (byte) ((value >> 0) & 0xff);
198 cursor += 8;
199 }
200
201 @Inline(value=Inline.When.AllArgumentsAreConstant)
202 private void putInt(int value) {
203 data[cursor + 0] = (byte) ((value >> 24) & 0xff);
204 data[cursor + 1] = (byte) ((value >> 16) & 0xff);
205 data[cursor + 2] = (byte) ((value >> 8) & 0xff);
206 data[cursor + 3] = (byte) ((value >> 0) & 0xff);
207 cursor += 4;
208 }
209
210 @Inline(value=Inline.When.AllArgumentsAreConstant)
211 protected void putIntAt(int index, int value) {
212 data[index + 0] = (byte) ((value >> 24) & 0xff);
213 data[index + 1] = (byte) ((value >> 16) & 0xff);
214 data[index + 2] = (byte) ((value >> 8) & 0xff);
215 data[index + 3] = (byte) ((value >> 0) & 0xff);
216 }
217
218 }