jdk

Форк
0
/
istream.cpp 
368 строк · 12.6 Кб
1
/*
2
 * Copyright (c) 2024, 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
#include "precompiled.hpp"
26
#include "memory/allocation.inline.hpp"
27
#include "runtime/orderAccess.hpp"
28
#include "utilities/istream.hpp"
29
#include "utilities/ostream.hpp"
30
#include "utilities/xmlstream.hpp"
31

32
#ifndef ASSERT
33
#define COV(casen) {}
34
#else //ASSERT
35
// Support for coverage testing.  Used by the gtest.
36
/* $ sed < istream.cpp '/^.* COV(\([A-Z][^)]*\)).*$/!d;s//COV_FN(\1)/' |
37
     tr '\12' ' ' | fold -sw72 | sed 's| $||;s|.*|  & \\|'
38
  */
39
#define DO_COV_CASES(COV_FN) \
40
  COV_FN(NXT_L) COV_FN(NXT_N) COV_FN(FIB_P) COV_FN(FIB_E) COV_FN(FIB_N) \
41
  COV_FN(FIB_L) COV_FN(PFB_C) COV_FN(PFB_P) COV_FN(PFB_A) \
42
  COV_FN(PFB_G) COV_FN(PFB_H) COV_FN(SBC_C) COV_FN(SBC_B) COV_FN(SBC_N) \
43
  COV_FN(SBC_L) COV_FN(EXB_R) COV_FN(EXB_A)
44
  /**/
45
#define COV_COUNT(casename) coverage_case_##casename
46
#define DECLARE_COV_CASE(casename) static int COV_COUNT(casename);
47
DO_COV_CASES(DECLARE_COV_CASE)
48
#undef DECLARE_COV_CASE
49

50
static int current_coverage_mode = 0;
51
#define COV(casename) {                                 \
52
    if (current_coverage_mode != 0) {                   \
53
      COV_COUNT(casename)++;                            \
54
    }                                                  }
55
#endif //ASSERT
56

57
bool inputStream::next() {
58
  // We have to look at the current line first, just in case nobody
59
  // actually called current_line() or done().
60
  preload();
61
  if (definitely_done()) {
62
    return false;         // OK to call this->next() after done is true
63
  }
64
  // current line is at buffer[beg..end]; now skip past its '\0'
65
  assert(have_current_line(), "");
66

67
  set_buffer_content(_next, _content_end);
68
  if (!need_to_read()) {  // any next line was already in the buffer
69
    COV(NXT_L);
70
    assert(have_current_line(), "");
71
    return true;
72
  } else {                // go back to the source for more
73
    COV(NXT_N);
74
    return fill_buffer();
75
  }
76
}
77

78
void inputStream::set_done() {
79
  size_t end = _beg = _end = _content_end;
80
  _next = end + NEXT_PHANTOM;
81
  _line_ending = 0;
82
  assert(definitely_done(), "");
83
}
84

85
void inputStream::set_error(bool error_condition) {
86
  if (error_condition) {
87
    set_done();
88
    _input_state = IState::ERR_STATE;
89
    assert(error(), "");
90
  } else if (error()) {
91
    _input_state = definitely_done() ? IState::EOF_STATE : IState::NTR_STATE;
92
  }
93
}
94

95
void inputStream::clear_buffer() {
96
  _content_end = _beg = _end = _next = 0;
97
  _line_ending = 0;
98
}
99

100
const char* inputStream::next_content(size_t& next_content_length) const {
101
  assert(is_sane(), "");
102
  size_t len = buffered_content_length(false);
103
  next_content_length = len;
104
  return len == 0 ? "" : &_buffer[_next];
105
}
106

107
void inputStream::set_input(inputStream::Input* input) {
108
  clear_buffer();
109
  _input = input;
110
  _input_state = IState::NTR_STATE;
111
}
112

113
bool inputStream::fill_buffer() {
114
  size_t fill_offset, fill_length;
115
  assert(!definitely_done(), "");  // caller responsibility
116
  while (need_to_read()) {
117
    prepare_to_fill_buffer(fill_offset, fill_length);
118
    if (error())  return false;
119
    assert(fill_length > 0, "");
120
    assert(fill_offset < _buffer_size, "");
121
    assert(fill_offset + fill_length <= _buffer_size, "");
122
    size_t nr = 0;
123
    if (_input != nullptr && _input_state == IState::NTR_STATE) {
124
      nr = _input->read(&_buffer[fill_offset], fill_length);
125
      if (nr == 0)  _input_state = IState::EOF_STATE;  // do not get EOF twice
126
    }
127
    bool last_partial = false;
128
    if (nr > 0) {
129
      fill_offset += nr;
130
    } else if (_beg == _end) {  // no partial line, so end it now
131
      // we hit the end of the file (or there was never anything there)
132
      COV(FIB_P);
133
      assert(!definitely_done(), "");
134
      set_done();
135
      assert(definitely_done(), "");
136
      return false;
137
    } else {
138
      // pretend to read a newline, to complete the last partial line
139
      COV(FIB_E);
140
      _buffer[fill_offset++] = '\n';  // insert phantom newline
141
      last_partial = true;
142
    }
143
    set_buffer_content(_beg, fill_offset);
144
    assert(!definitely_done(), "");
145
    if (need_to_read()) { COV(FIB_N); }
146
    else                { COV(FIB_L); }
147
    if (last_partial) {
148
      assert(have_current_line(), "");
149
      _line_ending = 0;
150
      _content_end -= 1;  // reverse insertion of phantom newline
151
      assert(_next == _content_end + NEXT_PHANTOM, "");
152
      assert(have_current_line(), "");
153
    }
154
  }
155
  return true;
156
}
157

158
// Find some space in the buffer for reading.  If there is already a
159
// partial line in the buffer, new space must follow it immediately.
160
// The partial line is between _beg and _end, and no other parts of
161
// the buffer are in use.
162
void inputStream::prepare_to_fill_buffer(size_t& fill_offset,
163
                                         size_t& fill_length) {
164
  assert(need_to_read(), "");  // _next pointer out of the way
165
  size_t end = _content_end;
166
  if (_beg == end) { // if no partial line present...
167
    COV(PFB_C);
168
    clear_buffer();
169
    fill_offset = 0;
170
    fill_length = _buffer_size;
171
    return;   // use the whole buffer
172
  }
173
  // at this point we have a pending line that needs more input
174
  if (_beg > 0 && (_input != nullptr || end == _buffer_size)) {
175
    COV(PFB_P);
176
    // compact the buffer by overwriting characters from previous lines
177
    size_t shift_left = _beg;
178
    ::memmove(_buffer, _buffer + shift_left, _content_end - _beg);
179
    _beg -= shift_left;
180
    _end -= shift_left;
181
    _next -= shift_left;
182
    _content_end -= shift_left;
183
    end = _content_end;
184
  }
185
  if (end < _buffer_size) {
186
    COV(PFB_A);
187
    fill_offset = end;
188
    fill_length = _buffer_size - end;
189
    return;   // use the whole buffer except partial line at the beginning
190
  }
191
  // the whole buffer contains a partial line, which means we must expand
192
  COV(PFB_G);
193
  size_t new_size = (_buffer_size < BIG_SIZE ? BIG_SIZE
194
                     : _buffer_size + _buffer_size / 2);
195
  assert(new_size > _buffer_size, "");
196
  if (expand_buffer(new_size)) {
197
    COV(PFB_H);
198
    fill_offset = end;
199
    fill_length = _buffer_size - end;
200
    return;   // use the expanded buffer, except the partial line
201
  }
202
  // no recovery from failed allocation; just set the error state and bail
203
  set_error();
204
}
205

206
// The only buffer content is between the given offsets.
207
// Set _beg, _end, _next, and _content_end appropriately.
208
void inputStream::set_buffer_content(size_t content_start,
209
                                     size_t content_end) {
210
  assert(content_end <= _buffer_size, "");
211
  assert(content_start <= content_end + NEXT_PHANTOM, "");
212
  if (content_start >= content_end) {   // empty content; clear buffer
213
    COV(SBC_C);
214
    clear_buffer();
215
    return;
216
  }
217
  COV(SBC_B);
218
  size_t content_len = content_end - content_start;
219
  _beg = content_start;
220
  _content_end = content_end;
221

222
  // this is where we scan for newlines
223
  char* nl = (char*) memchr(&_buffer[content_start], '\n', content_len);
224
  if (nl == nullptr) {
225
    COV(SBC_N);
226
    _next = _end = content_end;
227
    _line_ending = 0;
228
    assert(need_to_read(), "");
229
  } else {
230
    COV(SBC_L);
231
    *nl = '\0';  // so that this->current_line() will work
232
    ++_line_count;
233
    size_t end = nl - &_buffer[0];
234
    _next = end + 1;
235
    assert(_next != _content_end + NEXT_PHANTOM, "");
236
    if (end > content_start && nl[-1] == '\r') { // yuck
237
      // again, for this->current_line(), remove '\r' before '\n'
238
      nl[-1] = '\0';
239
      --end;
240
      // Note: we could treat '\r' alone as a line ending on some
241
      // platforms, but that is way too much work.  Newline '\n' is
242
      // supported everywhere, and some tools insist on accompanying
243
      // it with return as well, so we remove that.  But return '\r'
244
      // by itself is an obsolete format, and also inconsistent with
245
      // outputStream, which standarizes on '\n' and never emits '\r'.
246
      // Postel's law suggests that we write '\n' only and grudgingly
247
      // accept '\r' before '\n'.
248
    }
249
    _end = end;  // now this->current_line() points to buf[beg..end]
250
    _line_ending = (int)(_next - end);
251
    assert(have_current_line(), "");
252
    assert(current_line() == &_buffer[_beg], "");
253
    assert(current_line_length() == _end - _beg, "");
254
  }
255
}
256

257
// Return true iff we expanded the buffer to the given length.
258
bool inputStream::expand_buffer(size_t new_length) {
259
  assert(new_length > _buffer_size, "");
260
  char* new_buf = nullptr;
261
  assert(new_length > sizeof(_small_buffer), "");
262
  if (_buffer == &_small_buffer[0]) {
263
    // fresh alloc from c-heap
264
    COV(EXB_A);
265
    new_buf = NEW_C_HEAP_ARRAY(char, new_length, mtInternal);
266
    assert(new_buf != nullptr, "would have exited VM if OOM");
267
    if (_content_end > 0) {
268
      assert(_content_end <= _buffer_size, "");
269
      ::memcpy(new_buf, _buffer, _content_end);  // copy only the active content
270
    }
271
  } else {
272
    // realloc
273
    COV(EXB_R);
274
    new_buf = REALLOC_C_HEAP_ARRAY(char, _buffer, new_length, mtInternal);
275
    assert(new_buf != nullptr, "would have exited VM if OOM");
276
  }
277

278
  if (new_buf == nullptr) {
279
    return false;   // do not further update _buffer etc.
280
  }
281
  _buffer = new_buf;
282
  _buffer_size = new_length;
283
  return true;
284
}
285

286
inputStream::~inputStream() {
287
  if (has_c_heap_buffer()) {
288
    FreeHeap(_buffer);
289
    DEBUG_ONLY(_buffer = (char*)((uintptr_t)0xdeadbeef)); // sanity
290
  }
291
}
292

293
#ifdef ASSERT
294
void inputStream::dump(const char* what) {
295
  int diff = (int)(_end - _beg);
296
  if (!_buffer || _beg > _buffer_size || _end > _buffer_size)
297
    diff = 0;
298

299
  bool ntr = (_next == _end),
300
       hcl = (_beg < _content_end && _end < _next),
301
       ddn = (_beg == _content_end && _next > _content_end);
302
  tty->print_cr("%s%sistream %s%s%s%s%s [%d<%.*s>%d/%d..%d] LE=%d,"
303
                " B=%llx%s[%d], LN=%d, CH=%d",
304
                what ? what : "", what ? ": " : "",
305
                _buffer == nullptr ? "U" : "",
306
                ntr ? "R" : "",
307
                hcl ? "L" : "",
308
                ddn ? "D" : "",
309
                (_next < _content_end ? "" :
310
                 _next == _content_end ? "N" : "P"),
311
                (int)_beg,
312
                diff < 0 ? 0 : diff > 10 ? 10 : diff,
313
                _buffer ? &_buffer[_beg] : "",
314
                (int)_end, (int)_next, (int)_content_end,
315
                _line_ending,
316
                (unsigned long long)(intptr_t)_buffer,
317
                _buffer == _small_buffer ? "(SB)" : "",
318
                (int)_buffer_size,
319
                (int)_line_count,
320
                has_c_heap_buffer());
321
  assert(is_sane(), "");
322
}
323
#endif
324

325
#ifdef ASSERT
326
// More support for coverage testing.
327
int inputStream::coverage_mode(int start,
328
                               int& cases, int& total, int& zeroes) {
329
  int old_mode = current_coverage_mode;
330
  current_coverage_mode = start;
331
  int num_cases = 0, zero_count = 0, case_count = 0;
332
#define COUNT_COV_CASE(casename) {              \
333
    int tem = COV_COUNT(casename);              \
334
    case_count += tem;                          \
335
    if (tem == 0)  ++zero_count;                \
336
    num_cases++;                                \
337
  }
338
  DO_COV_CASES(COUNT_COV_CASE)
339
#undef COUNT_COV_CASE
340
  if (start < 0) {
341
    tty->print("istream coverage:");
342
    #define PRINT_COV_CASE(casename) \
343
      tty->print(" %s:%d", #casename, COV_COUNT(casename));
344
    DO_COV_CASES(PRINT_COV_CASE)
345
    tty->cr();
346
    #undef PRINT_COV_CASE
347
    if (zero_count != 0) {
348
      case_count = -case_count;
349
      #define ZERO_COV_CASE(casename)                  \
350
        if (COV_COUNT(casename) == 0)                  \
351
          tty->print_cr("%s: no coverage for %s",      \
352
                        __FILE__, #casename);          \
353
      DO_COV_CASES(ZERO_COV_CASE)
354
      #undef ZERO_COV_CASE
355
    }
356
  }
357
  if (start >= 2 || start < 0) {
358
    #define CLEAR_COV_CASE(casename) \
359
       COV_COUNT(casename) = 0;
360
    DO_COV_CASES(CLEAR_COV_CASE)
361
    #undef CLEAR_COV_CASE
362
  }
363
  cases  = num_cases;
364
  total  = case_count;
365
  zeroes = zero_count;
366
  return old_mode;
367
}
368
#endif //ASSERT
369

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.