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 015package com.ibm.tuningfork.tracegen.chunk; 016 017import java.io.IOException; 018import java.io.OutputStream; 019 020import org.jikesrvm.VM; 021import org.jikesrvm.runtime.Magic; 022import org.vmmagic.pragma.Inline; 023import org.vmmagic.pragma.Interruptible; 024import 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 039public 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}