/
githubmirror
/
panama-vector
Обзор
Документация
Войти
/
githubmirror
/
panama-vector
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/hotspot/share/utilities/istream.cpp
361 строка
12 KB
Stefan Karlsson
8382401: Remove return type parameters from FREE_ and REALLOC_ macros
20 апр 2026, 11:42
20 апр 2026, 11:42
abd3d46
Код
Авторство
О чём код?
/* * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #include "memory/allocation.inline.hpp" #include "runtime/orderAccess.hpp" #include "utilities/istream.hpp" #include "utilities/ostream.hpp" #include "utilities/xmlstream.hpp" #ifndef ASSERT #define COV(casen) {} #else //ASSERT // Support for coverage testing. Used by the gtest. /* $ sed < istream.cpp '/^.* COV(\([A-Z][^)]*\)).*$/!d;s//COV_FN(\1)/' | tr '\12' ' ' | fold -sw72 | sed 's| $||;s|.*| & \\|' */ #define DO_COV_CASES(COV_FN) \ COV_FN(NXT_L) COV_FN(NXT_N) COV_FN(FIB_P) COV_FN(FIB_E) COV_FN(FIB_N) \ COV_FN(FIB_L) COV_FN(PFB_C) COV_FN(PFB_P) COV_FN(PFB_A) \ COV_FN(PFB_G) COV_FN(PFB_H) COV_FN(SBC_C) COV_FN(SBC_B) COV_FN(SBC_N) \ COV_FN(SBC_L) COV_FN(EXB_R) COV_FN(EXB_A) /**/ #define COV_COUNT(casename) coverage_case_##casename #define DECLARE_COV_CASE(casename) static int COV_COUNT(casename); DO_COV_CASES(DECLARE_COV_CASE) #undef DECLARE_COV_CASE static int current_coverage_mode = 0; #define COV(casename) { \ if (current_coverage_mode != 0) { \ COV_COUNT(casename)++; \ } } #endif //ASSERT bool inputStream::next() { // We have to look at the current line first, just in case nobody // actually called current_line() or done(). preload(); if (definitely_done()) { return false; // OK to call this->next() after done is true } // current line is at buffer[beg..end]; now skip past its '\0' assert(have_current_line(), ""); set_buffer_content(_next, _content_end); if (!need_to_read()) { // any next line was already in the buffer COV(NXT_L); assert(have_current_line(), ""); return true; } else { // go back to the source for more COV(NXT_N); return fill_buffer(); } } void inputStream::set_done() { size_t end = _beg = _end = _content_end; _next = end + NEXT_PHANTOM; assert(definitely_done(), ""); } void inputStream::set_error(bool error_condition) { if (error_condition) { set_done(); _input_state = IState::ERR_STATE; assert(error(), ""); } else if (error()) { _input_state = definitely_done() ? IState::EOF_STATE : IState::NTR_STATE; } } void inputStream::clear_buffer() { _content_end = _beg = _end = _next = 0; } const char* inputStream::next_content(size_t& next_content_length) const { assert(is_sane(), ""); size_t len = buffered_content_length(false); next_content_length = len; return len == 0 ? "" : &_buffer[_next]; } void inputStream::set_input(inputStream::Input* input) { clear_buffer(); _input = input; _input_state = IState::NTR_STATE; } bool inputStream::fill_buffer() { size_t fill_offset, fill_length; assert(!definitely_done(), ""); // caller responsibility while (need_to_read()) { prepare_to_fill_buffer(fill_offset, fill_length); if (error()) return false; assert(fill_length > 0, ""); assert(fill_offset < _buffer_size, ""); assert(fill_offset + fill_length <= _buffer_size, ""); size_t nr = 0; if (_input != nullptr && _input_state == IState::NTR_STATE) { nr = _input->read(&_buffer[fill_offset], fill_length); if (nr == 0) _input_state = IState::EOF_STATE; // do not get EOF twice } bool last_partial = false; if (nr > 0) { fill_offset += nr; } else if (_beg == _end) { // no partial line, so end it now // we hit the end of the file (or there was never anything there) COV(FIB_P); assert(!definitely_done(), ""); set_done(); assert(definitely_done(), ""); return false; } else { // pretend to read a newline, to complete the last partial line COV(FIB_E); _buffer[fill_offset++] = '\n'; // insert phantom newline last_partial = true; } set_buffer_content(_beg, fill_offset); assert(!definitely_done(), ""); if (need_to_read()) { COV(FIB_N); } else { COV(FIB_L); } if (last_partial) { assert(have_current_line(), ""); _content_end -= 1; // reverse insertion of phantom newline assert(_next == _content_end + NEXT_PHANTOM, ""); assert(have_current_line(), ""); } } return true; } // Find some space in the buffer for reading. If there is already a // partial line in the buffer, new space must follow it immediately. // The partial line is between _beg and _end, and no other parts of // the buffer are in use. void inputStream::prepare_to_fill_buffer(size_t& fill_offset, size_t& fill_length) { assert(need_to_read(), ""); // _next pointer out of the way size_t end = _content_end; if (_beg == end) { // if no partial line present... COV(PFB_C); clear_buffer(); fill_offset = 0; fill_length = _buffer_size; return; // use the whole buffer } // at this point we have a pending line that needs more input if (_beg > 0 && (_input != nullptr || end == _buffer_size)) { COV(PFB_P); // compact the buffer by overwriting characters from previous lines size_t shift_left = _beg; ::memmove(_buffer, _buffer + shift_left, _content_end - _beg); _beg -= shift_left; _end -= shift_left; _next -= shift_left; _content_end -= shift_left; end = _content_end; } if (end < _buffer_size) { COV(PFB_A); fill_offset = end; fill_length = _buffer_size - end; return; // use the whole buffer except partial line at the beginning } // the whole buffer contains a partial line, which means we must expand COV(PFB_G); size_t new_size = (_buffer_size < BIG_SIZE ? BIG_SIZE : _buffer_size + _buffer_size / 2); assert(new_size > _buffer_size, ""); if (expand_buffer(new_size)) { COV(PFB_H); fill_offset = end; fill_length = _buffer_size - end; return; // use the expanded buffer, except the partial line } // no recovery from failed allocation; just set the error state and bail set_error(); } // The only buffer content is between the given offsets. // Set _beg, _end, _next, and _content_end appropriately. void inputStream::set_buffer_content(size_t content_start, size_t content_end) { assert(content_end <= _buffer_size, ""); assert(content_start <= content_end + NEXT_PHANTOM, ""); if (content_start >= content_end) { // empty content; clear buffer COV(SBC_C); clear_buffer(); return; } COV(SBC_B); size_t content_len = content_end - content_start; _beg = content_start; _content_end = content_end; // this is where we scan for newlines char* nl = (char*) memchr(&_buffer[content_start], '\n', content_len); if (nl == nullptr) { COV(SBC_N); _next = _end = content_end; assert(need_to_read(), ""); } else { COV(SBC_L); *nl = '\0'; // so that this->current_line() will work ++_line_count; size_t end = nl - &_buffer[0]; _next = end + 1; assert(_next != _content_end + NEXT_PHANTOM, ""); if (end > content_start && nl[-1] == '\r') { // yuck // again, for this->current_line(), remove '\r' before '\n' nl[-1] = '\0'; --end; // Note: we could treat '\r' alone as a line ending on some // platforms, but that is way too much work. Newline '\n' is // supported everywhere, and some tools insist on accompanying // it with return as well, so we remove that. But return '\r' // by itself is an obsolete format, and also inconsistent with // outputStream, which standarizes on '\n' and never emits '\r'. // Postel's law suggests that we write '\n' only and grudgingly // accept '\r' before '\n'. } _end = end; // now this->current_line() points to buf[beg..end] assert(have_current_line(), ""); assert(current_line() == &_buffer[_beg], ""); assert(current_line_length() == _end - _beg, ""); } } // Return true iff we expanded the buffer to the given length. bool inputStream::expand_buffer(size_t new_length) { assert(new_length > _buffer_size, ""); char* new_buf = nullptr; assert(new_length > sizeof(_small_buffer), ""); if (_buffer == &_small_buffer[0]) { // fresh alloc from c-heap COV(EXB_A); new_buf = NEW_C_HEAP_ARRAY(char, new_length, mtInternal); assert(new_buf != nullptr, "would have exited VM if OOM"); if (_content_end > 0) { assert(_content_end <= _buffer_size, ""); ::memcpy(new_buf, _buffer, _content_end); // copy only the active content } } else { // realloc COV(EXB_R); new_buf = REALLOC_C_HEAP_ARRAY(_buffer, new_length, mtInternal); assert(new_buf != nullptr, "would have exited VM if OOM"); } if (new_buf == nullptr) { return false; // do not further update _buffer etc. } _buffer = new_buf; _buffer_size = new_length; return true; } inputStream::~inputStream() { if (has_c_heap_buffer()) { FreeHeap(_buffer); DEBUG_ONLY(_buffer = (char*)((uintptr_t)0xdeadbeef)); // sanity } } #ifdef ASSERT void inputStream::dump(const char* what) { int diff = (int)(_end - _beg); if (!_buffer || _beg > _buffer_size || _end > _buffer_size) diff = 0; bool ntr = (_next == _end), hcl = (_beg < _content_end && _end < _next), ddn = (_beg == _content_end && _next > _content_end); tty->print_cr("%s%sistream %s%s%s%s%s [%d<%.*s>%d/%d..%d] " " B=%llx%s[%d], LN=%d, CH=%d", what ? what : "", what ? ": " : "", _buffer == nullptr ? "U" : "", ntr ? "R" : "", hcl ? "L" : "", ddn ? "D" : "", (_next < _content_end ? "" : _next == _content_end ? "N" : "P"), (int)_beg, diff < 0 ? 0 : diff > 10 ? 10 : diff, _buffer ? &_buffer[_beg] : "", (int)_end, (int)_next, (int)_content_end, (unsigned long long)(intptr_t)_buffer, _buffer == _small_buffer ? "(SB)" : "", (int)_buffer_size, (int)_line_count, has_c_heap_buffer()); assert(is_sane(), ""); } #endif #ifdef ASSERT // More support for coverage testing. int inputStream::coverage_mode(int start, int& cases, int& total, int& zeroes) { int old_mode = current_coverage_mode; current_coverage_mode = start; int num_cases = 0, zero_count = 0, case_count = 0; #define COUNT_COV_CASE(casename) { \ int tem = COV_COUNT(casename); \ case_count += tem; \ if (tem == 0) ++zero_count; \ num_cases++; \ } DO_COV_CASES(COUNT_COV_CASE) #undef COUNT_COV_CASE if (start < 0) { tty->print("istream coverage:"); #define PRINT_COV_CASE(casename) \ tty->print(" %s:%d", #casename, COV_COUNT(casename)); DO_COV_CASES(PRINT_COV_CASE) tty->cr(); #undef PRINT_COV_CASE if (zero_count != 0) { case_count = -case_count; #define ZERO_COV_CASE(casename) \ if (COV_COUNT(casename) == 0) \ tty->print_cr("%s: no coverage for %s", \ __FILE__, #casename); \ DO_COV_CASES(ZERO_COV_CASE) #undef ZERO_COV_CASE } } if (start >= 2 || start < 0) { #define CLEAR_COV_CASE(casename) \ COV_COUNT(casename) = 0; DO_COV_CASES(CLEAR_COV_CASE) #undef CLEAR_COV_CASE } cases = num_cases; total = case_count; zeroes = zero_count; return old_mode; } #endif //ASSERT