1/*
2 * Copyright (c) 1997, 2010, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#ifndef SHARE_VM_CODE_COMPRESSEDSTREAM_HPP
26#define SHARE_VM_CODE_COMPRESSEDSTREAM_HPP
27
28#include "memory/allocation.hpp"
29
30// Simple interface for filing out and filing in basic types
31// Used for writing out and reading in debugging information.
32
33class CompressedStream : public ResourceObj {
34  friend class VMStructs;
35 protected:
36  u_char* _buffer;
37  int     _position;
38
39  enum {
40    // Constants for UNSIGNED5 coding of Pack200
41    lg_H = 6, H = 1<<lg_H,    // number of high codes (64)
42    L = (1<<BitsPerByte)-H,   // number of low codes (192)
43    MAX_i = 4                 // bytes are numbered in (0..4), max 5 bytes
44  };
45
46  // these inlines are defined only in compressedStream.cpp
47  static inline juint encode_sign(jint  value);  // for Pack200 SIGNED5
48  static inline jint  decode_sign(juint value);  // for Pack200 SIGNED5
49  static inline juint reverse_int(juint bits);   // to trim trailing float 0's
50
51 public:
52  CompressedStream(u_char* buffer, int position = 0) {
53    _buffer   = buffer;
54    _position = position;
55  }
56
57  u_char* buffer() const               { return _buffer; }
58
59  // Positioning
60  int position() const                 { return _position; }
61  void set_position(int position)      { _position = position; }
62};
63
64
65class CompressedReadStream : public CompressedStream {
66 private:
67  inline u_char read()                 { return _buffer[_position++]; }
68
69  // This encoding, called UNSIGNED5, is taken from J2SE Pack200.
70  // It assumes that most values have lots of leading zeroes.
71  // Very small values, in the range [0..191], code in one byte.
72  // Any 32-bit value (including negatives) can be coded, in
73  // up to five bytes.  The grammar is:
74  //    low_byte  = [0..191]
75  //    high_byte = [192..255]
76  //    any_byte  = low_byte | high_byte
77  //    coding = low_byte
78  //           | high_byte low_byte
79  //           | high_byte high_byte low_byte
80  //           | high_byte high_byte high_byte low_byte
81  //           | high_byte high_byte high_byte high_byte any_byte
82  // Each high_byte contributes six bits of payload.
83  // The encoding is one-to-one (except for integer overflow)
84  // and easy to parse and unparse.
85
86  jint read_int_mb(jint b0) {
87    int     pos = position() - 1;
88    u_char* buf = buffer() + pos;
89    assert(buf[0] == b0 && b0 >= L, "correctly called");
90    jint    sum = b0;
91    // must collect more bytes:  b[1]...b[4]
92    int lg_H_i = lg_H;
93    for (int i = 0; ; ) {
94      jint b_i = buf[++i]; // b_i = read(); ++i;
95      sum += b_i << lg_H_i;  // sum += b[i]*(64**i)
96      if (b_i < L || i == MAX_i) {
97        set_position(pos+i+1);
98        return sum;
99      }
100      lg_H_i += lg_H;
101    }
102  }
103
104 public:
105  CompressedReadStream(u_char* buffer, int position = 0)
106  : CompressedStream(buffer, position) {}
107
108  jboolean read_bool()                 { return (jboolean) read();      }
109  jbyte    read_byte()                 { return (jbyte   ) read();      }
110  jchar    read_char()                 { return (jchar   ) read_int();  }
111  jshort   read_short()                { return (jshort  ) read_signed_int(); }
112  jint     read_int()                  { jint   b0 = read();
113                                         if (b0 < L)  return b0;
114                                         else         return read_int_mb(b0);
115                                       }
116  jint     read_signed_int();
117  jfloat   read_float();               // jfloat_cast(reverse_int(read_int()))
118  jdouble  read_double();              // jdouble_cast(2*reverse_int(read_int))
119  jlong    read_long();                // jlong_from(2*read_signed_int())
120};
121
122
123class CompressedWriteStream : public CompressedStream {
124 private:
125  bool full() {
126    return _position >= _size;
127  }
128  void store(u_char b) {
129    _buffer[_position++] = b;
130  }
131  void write(u_char b) {
132    if (full()) grow();
133    store(b);
134  }
135  void grow();
136
137  void write_int_mb(jint value);  // UNSIGNED5 coding, 1-5 byte cases
138
139 protected:
140  int _size;
141
142 public:
143  CompressedWriteStream(int initial_size);
144  CompressedWriteStream(u_char* buffer, int initial_size, int position = 0)
145  : CompressedStream(buffer, position) { _size = initial_size; }
146
147  void write_bool(jboolean value)      { write(value);      }
148  void write_byte(jbyte value)         { write(value);      }
149  void write_char(jchar value)         { write_int(value); }
150  void write_short(jshort value)       { write_signed_int(value);  }
151  void write_int(jint value)           { if ((juint)value < L && !full())
152                                               store((u_char)value);
153                                         else  write_int_mb(value);  }
154  void write_signed_int(jint value);   // write_int(encode_sign(value))
155  void write_float(jfloat value);      // write_int(reverse_int(jint_cast(v)))
156  void write_double(jdouble value);    // write_int(reverse_int(<low,high>))
157  void write_long(jlong value);        // write_signed_int(<low,high>)
158};
159
160#endif // SHARE_VM_CODE_COMPRESSEDSTREAM_HPP
161