Skip to content

Instantly share code, notes, and snippets.

@qwwdfsad
Created March 17, 2026 11:13
Show Gist options
  • Select an option

  • Save qwwdfsad/c6e4f9530bae4c87ee6f795e6c4b62f6 to your computer and use it in GitHub Desktop.

Select an option

Save qwwdfsad/c6e4f9530bae4c87ee6f795e6c4b62f6 to your computer and use it in GitHub Desktop.
Subject: [PATCH] JSR-45 support
---
Index: src/hotspot/share/oops/instanceKlass.hpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp
--- a/src/hotspot/share/oops/instanceKlass.hpp (revision cb059a6b1b1686b7adcb2e88536060f4f7d47118)
+++ b/src/hotspot/share/oops/instanceKlass.hpp (date 1772629314300)
@@ -46,6 +46,7 @@
class DeoptimizationScope;
class klassItable;
class RecordComponent;
+class SourceMapInfo;
// An InstanceKlass is the VM level representation of a Java class.
// It contains all information needed for at class at execution runtime.
@@ -209,6 +210,10 @@
// it is stored in the instanceklass as a null-terminated UTF-8 string
const char* _source_debug_extension;
+ // Lazily parsed SMAP data from _source_debug_extension.
+ // Initialized on first use via Atomic::cmpxchg. Owned by this klass.
+ SourceMapInfo* _source_map_info;
+
// Number of heapOopSize words used by non-static fields in this klass
// (including inherited fields but after header_size()).
int _nonstatic_field_size;
@@ -686,6 +691,9 @@
const char* source_debug_extension() const { return _source_debug_extension; }
void set_source_debug_extension(const char* array, int length);
+ // Lazily-initialized parsed SMAP. Returns nullptr if no valid SMAP.
+ SourceMapInfo* source_map_info();
+
// nonstatic oop-map blocks
static int nonstatic_oop_map_size(unsigned int oop_map_count) {
return oop_map_count * OopMapBlock::size_in_words();
Index: src/hotspot/share/oops/instanceKlass.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
--- a/src/hotspot/share/oops/instanceKlass.cpp (revision cb059a6b1b1686b7adcb2e88536060f4f7d47118)
+++ b/src/hotspot/share/oops/instanceKlass.cpp (date 1772718701156)
@@ -40,6 +40,7 @@
#include "classfile/verifier.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
+#include "classfile/sourceDebugExtension.hpp"
#include "code/codeCache.hpp"
#include "code/dependencyContext.hpp"
#include "compiler/compilationPolicy.hpp"
@@ -2746,6 +2747,7 @@
// These are not allocated from metaspace. They are safe to set to null.
_source_debug_extension = nullptr;
+ _source_map_info = nullptr;
_dep_context = nullptr;
_osr_nmethods_head = nullptr;
#if INCLUDE_JVMTI
@@ -2989,6 +2991,8 @@
#endif
FREE_C_HEAP_ARRAY(char, _source_debug_extension);
+ delete _source_map_info;
+ _source_map_info = nullptr;
if (release_sub_metadata) {
constants()->release_C_heap_structures();
@@ -3019,6 +3023,33 @@
}
return nullptr;
}
+
+SourceMapInfo* InstanceKlass::source_map_info() {
+ // TODO race?
+ SourceMapInfo* info = _source_map_info;
+ if (info != nullptr) {
+ return info;
+ }
+ const char* sde = _source_debug_extension;
+ if (sde == nullptr) {
+ return nullptr;
+ }
+ // Parse on first access. Benign race: if two threads parse simultaneously,
+ // one result is discarded. The field is only written once (null -> valid).
+ // TODO slow if corrupted
+ // TODO can be even allocated directly?
+ info = new SourceMapInfo(sde);
+ if (!info->is_valid()) {
+ delete info;
+ return nullptr;
+ }
+ if (AtomicAccess::replace_if_null(&_source_map_info, info)) {
+ return info;
+ }
+ // Another thread won the race
+ delete info;
+ return _source_map_info;
+}
void InstanceKlass::set_source_debug_extension(const char* array, int length) {
if (array == nullptr) {
Index: src/hotspot/share/classfile/sourceDebugExtension.hpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/hotspot/share/classfile/sourceDebugExtension.hpp b/src/hotspot/share/classfile/sourceDebugExtension.hpp
new file mode 100644
--- /dev/null (date 1772628705444)
+++ b/src/hotspot/share/classfile/sourceDebugExtension.hpp (date 1772628705444)
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#ifndef SHARE_CLASSFILE_SOURCEDEBUGEXTENSION_HPP
+#define SHARE_CLASSFILE_SOURCEDEBUGEXTENSION_HPP
+
+#include "memory/allocation.hpp"
+
+// Parsed representation of a JSR-45 SourceDebugExtension (SMAP) attribute.
+// Used to translate Java line numbers and file names in stack traces
+// back to original source locations (e.g., Kotlin inline/suspend functions).
+//
+// Thread-safe: instances are immutable after construction.
+// Allocated on C-heap and cached on InstanceKlass.
+
+class SourceMapInfo : public CHeapObj<mtClass> {
+ public:
+ struct FileEntry {
+ int file_id;
+ char* source_name; // allocated, owned
+ char* source_path; // allocated, owned (may be nullptr)
+ };
+
+ struct LineEntry {
+ int jpls_start; // Java line range start
+ int jpls_end; // Java line range end (inclusive)
+ int jpls_line_inc; // Java line increment
+ int njpls_start; // Original source line start
+ int njpls_end; // Original source line end (inclusive)
+ int file_id; // Reference to FileEntry
+ };
+
+ struct StratumEntry {
+ char* id; // stratum name (allocated, owned)
+ int file_index; // start index in _files array
+ int line_index; // start index in _lines array
+ };
+
+ private:
+ bool _valid;
+
+ FileEntry* _files;
+ int _file_count;
+
+ LineEntry* _lines;
+ int _line_count;
+
+ StratumEntry* _strata;
+ int _stratum_count;
+
+ int _default_stratum_index;
+ int _base_stratum_index;
+
+ // Parser state (only used during construction)
+ const char* _sde; // input string (not owned)
+ const char* _pos; // current parse position
+ int _current_file_id;
+ bool _parse_error;
+
+ // Growable arrays during parsing
+ int _files_capacity;
+ int _lines_capacity;
+ int _strata_capacity;
+
+ // Parsing methods
+ void decode();
+ char peek();
+ char read();
+ void advance();
+ void ignore_white();
+ void ignore_line();
+ int read_number();
+ char* read_line(); // returns allocated copy
+ void syntax_error();
+
+ void create_java_stratum(const char* jpls_filename);
+ void stratum_section();
+ void file_section();
+ void line_section();
+ void ignore_section();
+ void file_line();
+ void line_line();
+
+ void store_stratum(const char* id);
+ void store_file(int file_id, const char* source_name, const char* source_path);
+ void store_line(int jpls_start, int jpls_end, int jpls_line_inc,
+ int njpls_start, int njpls_end, int file_id);
+
+ void ensure_file_capacity();
+ void ensure_line_capacity();
+ void ensure_stratum_capacity();
+
+ // Query helpers
+ int default_stratum_table_index() const;
+ int sti_line_table_index(int sti, int jpls_line) const;
+ int sti_line_number(int sti, int lti, int jpls_line) const;
+ int sti_file_id(int lti) const;
+ int find_file_index(int sti, int file_id) const;
+
+ public:
+ // Parse an SMAP string. Returns a valid SourceMapInfo on success,
+ // or one with is_valid()==false on parse error.
+ SourceMapInfo(const char* source_debug_extension);
+ ~SourceMapInfo();
+
+ bool is_valid() const { return _valid; }
+
+ // Result of a line translation query.
+ struct TranslationResult {
+ bool translated; // true if a mapping was found
+ int line_number; // translated line number
+ const char* source_name; // translated source file name (not owned, valid for lifetime of SourceMapInfo)
+ };
+
+ // Translate a Java line number using the default stratum.
+ // If no mapping exists, returns result with translated==false.
+ TranslationResult translate(int java_line_number) const;
+};
+
+#endif // SHARE_CLASSFILE_SOURCEDEBUGEXTENSION_HPP
Index: src/hotspot/share/classfile/sourceDebugExtension.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/hotspot/share/classfile/sourceDebugExtension.cpp b/src/hotspot/share/classfile/sourceDebugExtension.cpp
new file mode 100644
--- /dev/null (date 1772628757590)
+++ b/src/hotspot/share/classfile/sourceDebugExtension.cpp (date 1772628757590)
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "classfile/sourceDebugExtension.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/copy.hpp"
+
+#include <string.h>
+
+// Initial capacities for growable arrays during parsing
+static const int INIT_FILE_CAPACITY = 10;
+static const int INIT_LINE_CAPACITY = 100;
+static const int INIT_STRATUM_CAPACITY = 3;
+
+static char* alloc_string(const char* src) {
+ if (src == nullptr) return nullptr;
+ size_t len = strlen(src);
+ char* dst = NEW_C_HEAP_ARRAY(char, len + 1, mtClass);
+ memcpy(dst, src, len + 1);
+ return dst;
+}
+
+static char* alloc_string(const char* src, size_t len) {
+ char* dst = NEW_C_HEAP_ARRAY(char, len + 1, mtClass);
+ memcpy(dst, src, len);
+ dst[len] = '\0';
+ return dst;
+}
+
+// ============================================================================
+// Construction / Destruction
+// ============================================================================
+
+SourceMapInfo::SourceMapInfo(const char* source_debug_extension) :
+ _valid(false),
+ _files(nullptr),
+ _file_count(0),
+ _lines(nullptr),
+ _line_count(0),
+ _strata(nullptr),
+ _stratum_count(0),
+ _default_stratum_index(-1),
+ _base_stratum_index(-2),
+ _sde(source_debug_extension),
+ _pos(source_debug_extension),
+ _current_file_id(0),
+ _parse_error(false),
+ _files_capacity(0),
+ _lines_capacity(0),
+ _strata_capacity(0)
+{
+ if (_sde != nullptr && strlen(_sde) > 4) {
+ decode();
+ }
+}
+
+SourceMapInfo::~SourceMapInfo() {
+ for (int i = 0; i < _file_count; i++) {
+ FREE_C_HEAP_ARRAY(char, _files[i].source_name);
+ FREE_C_HEAP_ARRAY(char, _files[i].source_path);
+ }
+ for (int i = 0; i < _stratum_count; i++) {
+ FREE_C_HEAP_ARRAY(char, _strata[i].id);
+ }
+ FREE_C_HEAP_ARRAY(FileEntry, _files);
+ FREE_C_HEAP_ARRAY(LineEntry, _lines);
+ FREE_C_HEAP_ARRAY(StratumEntry, _strata);
+}
+
+// ============================================================================
+// Parser - low level
+// ============================================================================
+
+void SourceMapInfo::syntax_error() {
+ _parse_error = true;
+}
+
+char SourceMapInfo::peek() {
+ if (_parse_error || *_pos == '\0') {
+ syntax_error();
+ return '\0';
+ }
+ return *_pos;
+}
+
+char SourceMapInfo::read() {
+ if (_parse_error || *_pos == '\0') {
+ syntax_error();
+ return '\0';
+ }
+ return *_pos++;
+}
+
+void SourceMapInfo::advance() {
+ if (!_parse_error && *_pos != '\0') {
+ _pos++;
+ }
+}
+
+void SourceMapInfo::ignore_white() {
+ while (!_parse_error && (*_pos == ' ' || *_pos == '\t')) {
+ _pos++;
+ }
+}
+
+void SourceMapInfo::ignore_line() {
+ if (_parse_error) return;
+ char ch;
+ do {
+ ch = read();
+ if (_parse_error) return;
+ } while (ch != '\n' && ch != '\r');
+
+ // Check for CR LF
+ if (ch == '\r' && *_pos == '\n') {
+ _pos++;
+ }
+ ignore_white();
+}
+
+int SourceMapInfo::read_number() {
+ int value = 0;
+ ignore_white();
+ if (_parse_error) return 0;
+ while (*_pos >= '0' && *_pos <= '9') {
+ value = (value * 10) + (*_pos - '0');
+ _pos++;
+ }
+ ignore_white();
+ return value;
+}
+
+// Returns an allocated copy of the line content.
+char* SourceMapInfo::read_line() {
+ ignore_white();
+ if (_parse_error) return alloc_string("");
+
+ const char* start = _pos;
+ while (*_pos != '\n' && *_pos != '\r' && *_pos != '\0') {
+ _pos++;
+ }
+ size_t len = (size_t)(_pos - start);
+
+ // Consume line ending
+ if (*_pos == '\r') {
+ _pos++;
+ if (*_pos == '\n') _pos++;
+ } else if (*_pos == '\n') {
+ _pos++;
+ }
+ ignore_white();
+
+ return alloc_string(start, len);
+}
+
+// ============================================================================
+// Parser - storage
+// ============================================================================
+
+void SourceMapInfo::ensure_file_capacity() {
+ if (_file_count >= _files_capacity) {
+ int new_cap = (_files_capacity == 0) ? INIT_FILE_CAPACITY : _files_capacity * 2;
+ FileEntry* new_arr = NEW_C_HEAP_ARRAY(FileEntry, new_cap, mtClass);
+ if (_files != nullptr) {
+ memcpy(new_arr, _files, _file_count * sizeof(FileEntry));
+ FREE_C_HEAP_ARRAY(FileEntry, _files);
+ }
+ _files = new_arr;
+ _files_capacity = new_cap;
+ }
+}
+
+void SourceMapInfo::ensure_line_capacity() {
+ if (_line_count >= _lines_capacity) {
+ int new_cap = (_lines_capacity == 0) ? INIT_LINE_CAPACITY : _lines_capacity * 2;
+ LineEntry* new_arr = NEW_C_HEAP_ARRAY(LineEntry, new_cap, mtClass);
+ if (_lines != nullptr) {
+ memcpy(new_arr, _lines, _line_count * sizeof(LineEntry));
+ FREE_C_HEAP_ARRAY(LineEntry, _lines);
+ }
+ _lines = new_arr;
+ _lines_capacity = new_cap;
+ }
+}
+
+void SourceMapInfo::ensure_stratum_capacity() {
+ if (_stratum_count >= _strata_capacity) {
+ int new_cap = (_strata_capacity == 0) ? INIT_STRATUM_CAPACITY : _strata_capacity * 2;
+ StratumEntry* new_arr = NEW_C_HEAP_ARRAY(StratumEntry, new_cap, mtClass);
+ if (_strata != nullptr) {
+ memcpy(new_arr, _strata, _stratum_count * sizeof(StratumEntry));
+ FREE_C_HEAP_ARRAY(StratumEntry, _strata);
+ }
+ _strata = new_arr;
+ _strata_capacity = new_cap;
+ }
+}
+
+void SourceMapInfo::store_file(int file_id, const char* source_name, const char* source_path) {
+ ensure_file_capacity();
+ _files[_file_count].file_id = file_id;
+ _files[_file_count].source_name = alloc_string(source_name);
+ _files[_file_count].source_path = (source_path != nullptr) ? alloc_string(source_path) : nullptr;
+ _file_count++;
+}
+
+void SourceMapInfo::store_line(int jpls_start, int jpls_end, int jpls_line_inc,
+ int njpls_start, int njpls_end, int file_id) {
+ ensure_line_capacity();
+ _lines[_line_count].jpls_start = jpls_start;
+ _lines[_line_count].jpls_end = jpls_end;
+ _lines[_line_count].jpls_line_inc = jpls_line_inc;
+ _lines[_line_count].njpls_start = njpls_start;
+ _lines[_line_count].njpls_end = njpls_end;
+ _lines[_line_count].file_id = file_id;
+ _line_count++;
+}
+
+void SourceMapInfo::store_stratum(const char* id) {
+ // Remove redundant strata (nothing changed since last store)
+ if (_stratum_count > 0) {
+ if (_strata[_stratum_count - 1].file_index == _file_count &&
+ _strata[_stratum_count - 1].line_index == _line_count) {
+ FREE_C_HEAP_ARRAY(char, _strata[_stratum_count - 1].id);
+ _stratum_count--;
+ }
+ }
+ ensure_stratum_capacity();
+ _strata[_stratum_count].id = alloc_string(id);
+ _strata[_stratum_count].file_index = _file_count;
+ _strata[_stratum_count].line_index = _line_count;
+ _stratum_count++;
+ _current_file_id = 0;
+}
+
+// ============================================================================
+// Parser - sections
+// ============================================================================
+
+void SourceMapInfo::create_java_stratum(const char* jpls_filename) {
+ _base_stratum_index = _stratum_count;
+ store_stratum("Java");
+ store_file(1, jpls_filename, nullptr);
+ // Java line numbers cannot exceed 65535
+ store_line(1, 65536, 1, 1, 65536, 1);
+ store_stratum("Aux"); // sentinel in case no strata declared
+}
+
+void SourceMapInfo::file_line() {
+ if (_parse_error) return;
+
+ bool has_absolute = false;
+ if (peek() == '+') {
+ advance();
+ has_absolute = true;
+ }
+ int file_id = read_number();
+ char* source_name = read_line();
+ char* source_path = nullptr;
+ if (has_absolute) {
+ source_path = read_line();
+ }
+ store_file(file_id, source_name, source_path);
+ FREE_C_HEAP_ARRAY(char, source_name);
+ FREE_C_HEAP_ARRAY(char, source_path);
+}
+
+// Parse: <NJ-start-line> [ # <file-id> ] [ , <line-count> ] : <J-start-line> [ , <line-increment> ]
+void SourceMapInfo::line_line() {
+ if (_parse_error) return;
+
+ int line_count = 1;
+ int line_increment = 1;
+
+ int njpls_start = read_number();
+
+ if (!_parse_error && peek() == '#') {
+ advance();
+ _current_file_id = read_number();
+ }
+
+ if (!_parse_error && peek() == ',') {
+ advance();
+ line_count = read_number();
+ }
+
+ if (_parse_error || read() != ':') {
+ syntax_error();
+ return;
+ }
+
+ int jpls_start = read_number();
+
+ if (!_parse_error && peek() == ',') {
+ advance();
+ line_increment = read_number();
+ }
+
+ ignore_line();
+
+ if (!_parse_error) {
+ store_line(jpls_start,
+ jpls_start + (line_count * line_increment) - 1,
+ line_increment,
+ njpls_start,
+ njpls_start + line_count - 1,
+ _current_file_id);
+ }
+}
+
+void SourceMapInfo::file_section() {
+ ignore_line();
+ while (!_parse_error && peek() != '*') {
+ file_line();
+ }
+}
+
+void SourceMapInfo::line_section() {
+ ignore_line();
+ while (!_parse_error && peek() != '*') {
+ line_line();
+ }
+}
+
+void SourceMapInfo::stratum_section() {
+ char* id = read_line();
+ store_stratum(id);
+ FREE_C_HEAP_ARRAY(char, id);
+}
+
+void SourceMapInfo::ignore_section() {
+ ignore_line();
+ while (!_parse_error && peek() != '*') {
+ ignore_line();
+ }
+}
+
+// ============================================================================
+// Parser - main entry
+// ============================================================================
+
+void SourceMapInfo::decode() {
+ // Check for "SMAP" header
+ if (read() != 'S' || read() != 'M' || read() != 'A' || read() != 'P') {
+ return; // not SMAP data
+ }
+ if (_parse_error) return;
+
+ ignore_line(); // rest of SMAP line
+
+ char* jpls_filename = read_line();
+ char* default_stratum_id = read_line();
+
+ create_java_stratum(jpls_filename);
+
+ while (!_parse_error) {
+ if (read() != '*') {
+ syntax_error();
+ break;
+ }
+ char section = read();
+ if (_parse_error) break;
+
+ switch (section) {
+ case 'S':
+ stratum_section();
+ break;
+ case 'F':
+ file_section();
+ break;
+ case 'L':
+ line_section();
+ break;
+ case 'E':
+ // End marker - finalize
+ store_stratum("*terminator*");
+ _valid = true;
+ // Resolve default stratum index
+ _default_stratum_index = -1;
+ for (int i = 0; i < _stratum_count - 1; i++) {
+ if (strcmp(_strata[i].id, default_stratum_id) == 0) {
+ _default_stratum_index = i;
+ break;
+ }
+ }
+ FREE_C_HEAP_ARRAY(char, jpls_filename);
+ FREE_C_HEAP_ARRAY(char, default_stratum_id);
+ return;
+ default:
+ ignore_section();
+ break;
+ }
+ }
+
+ // Parse error path
+ FREE_C_HEAP_ARRAY(char, jpls_filename);
+ FREE_C_HEAP_ARRAY(char, default_stratum_id);
+}
+
+// ============================================================================
+// Query methods
+// ============================================================================
+
+int SourceMapInfo::default_stratum_table_index() const {
+ return _default_stratum_index;
+}
+
+int SourceMapInfo::sti_line_table_index(int sti, int jpls_line) const {
+ int line_start = _strata[sti].line_index;
+ int line_end = _strata[sti + 1].line_index; // one past end (guaranteed by terminator stratum)
+ for (int i = line_start; i < line_end; i++) {
+ if (jpls_line >= _lines[i].jpls_start && jpls_line <= _lines[i].jpls_end) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int SourceMapInfo::sti_line_number(int sti, int lti, int jpls_line) const {
+ return _lines[lti].njpls_start +
+ ((jpls_line - _lines[lti].jpls_start) / _lines[lti].jpls_line_inc);
+}
+
+int SourceMapInfo::sti_file_id(int lti) const {
+ return _lines[lti].file_id;
+}
+
+int SourceMapInfo::find_file_index(int sti, int file_id) const {
+ int file_start = _strata[sti].file_index;
+ int file_end = _strata[sti + 1].file_index;
+ for (int i = file_start; i < file_end; i++) {
+ if (_files[i].file_id == file_id) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+SourceMapInfo::TranslationResult SourceMapInfo::translate(int java_line_number) const {
+ TranslationResult result = { false, java_line_number, nullptr };
+
+ if (!_valid) return result;
+
+ int sti = default_stratum_table_index();
+ if (sti < 0 || sti == _base_stratum_index) {
+ // No default stratum or default is Java — no translation
+ return result;
+ }
+
+ int lti = sti_line_table_index(sti, java_line_number);
+ if (lti < 0) {
+ // No mapping for this line
+ return result;
+ }
+
+ result.translated = true;
+ result.line_number = sti_line_number(sti, lti, java_line_number);
+
+ int file_id = sti_file_id(lti);
+ int fi = find_file_index(sti, file_id);
+ if (fi >= 0) {
+ result.source_name = _files[fi].source_name;
+ }
+
+ return result;
+}
Index: src/hotspot/share/classfile/javaClasses.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp
--- a/src/hotspot/share/classfile/javaClasses.cpp (revision cb059a6b1b1686b7adcb2e88536060f4f7d47118)
+++ b/src/hotspot/share/classfile/javaClasses.cpp (date 1772629452697)
@@ -38,6 +38,7 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
+#include "classfile/sourceDebugExtension.hpp"
#include "code/debugInfo.hpp"
#include "code/dependencyContext.hpp"
#include "code/pcDesc.hpp"
@@ -3152,6 +3153,21 @@
}
}
line_number = Backtrace::get_line_number(method(), bci);
+
+ // Translate through JSR-45 SMAP if available and enabled
+ if (TranslateSourceDebugExtension && line_number > 0) {
+ SourceMapInfo* smap = holder->source_map_info();
+ if (smap != nullptr) {
+ SourceMapInfo::TranslationResult tr = smap->translate(line_number);
+ if (tr.translated) {
+ line_number = tr.line_number;
+ if (tr.source_name != nullptr) {
+ // Override the source file name with the SMAP-translated one
+ source_file = StringTable::intern(tr.source_name, CHECK);
+ }
+ }
+ }
+ }
}
#if INCLUDE_JVMCI
Index: src/hotspot/share/classfile/classFileParser.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp
--- a/src/hotspot/share/classfile/classFileParser.cpp (revision cb059a6b1b1686b7adcb2e88536060f4f7d47118)
+++ b/src/hotspot/share/classfile/classFileParser.cpp (date 1772628663042)
@@ -2861,8 +2861,8 @@
const u1* const sde_buffer = cfs->current();
assert(sde_buffer != nullptr, "null sde buffer");
- // Don't bother storing it if there is no way to retrieve it
- if (JvmtiExport::can_get_source_debug_extension()) {
+ // Store it if JVMTI needs it or if SMAP stack trace translation is enabled
+ if (JvmtiExport::can_get_source_debug_extension() || TranslateSourceDebugExtension) {
assert((length+1) > length, "Overflow checking");
u1* const sde = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, u1, length+1);
for (int i = 0; i < length; i++) {
Index: src/hotspot/share/runtime/globals.hpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
--- a/src/hotspot/share/runtime/globals.hpp (revision cb059a6b1b1686b7adcb2e88536060f4f7d47118)
+++ b/src/hotspot/share/runtime/globals.hpp (date 1772628652495)
@@ -180,6 +180,10 @@
"Print information about Java monitor locks when the stacks are " \
"dumped") \
\
+ product(bool, TranslateSourceDebugExtension, true, \
+ "Translate line numbers and file names in stack traces using " \
+ "JSR-45 SourceDebugExtension (SMAP) data") \
+ \
product_pd(bool, UseLargePages, \
"Use large page memory") \
\
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment