changeset 54042:6dd6f988b4e4

8219860: Cleanup ClassFileParser::parse_linenumber_table Reviewed-by: rehn, lfoltan, hseigel
author redestad
date Fri, 08 Mar 2019 23:02:06 +0100
parents bba6644b6fe3
children 0324b3756aa2
files src/hotspot/share/classfile/classFileParser.cpp src/hotspot/share/classfile/classFileParser.hpp src/hotspot/share/classfile/classFileStream.cpp src/hotspot/share/classfile/classFileStream.hpp src/hotspot/share/code/compressedStream.cpp src/hotspot/share/code/compressedStream.hpp src/hotspot/share/oops/method.cpp src/hotspot/share/oops/method.hpp src/hotspot/share/oops/method.inline.hpp src/hotspot/share/runtime/relocator.cpp
diffstat 10 files changed, 85 insertions(+), 332 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/classfile/classFileParser.cpp	Fri Mar 08 16:21:16 2019 -0500
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Fri Mar 08 23:02:06 2019 +0100
@@ -52,7 +52,7 @@
 #include "oops/klass.inline.hpp"
 #include "oops/klassVtable.hpp"
 #include "oops/metadata.hpp"
-#include "oops/method.hpp"
+#include "oops/method.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "prims/jvmtiExport.hpp"
@@ -1974,46 +1974,6 @@
   return localvariable_table_start;
 }
 
-
-void ClassFileParser::parse_type_array(u2 array_length,
-                                       u4 code_length,
-                                       u4* const u1_index,
-                                       u4* const u2_index,
-                                       u1* const u1_array,
-                                       u2* const u2_array,
-                                       TRAPS) {
-  const ClassFileStream* const cfs = _stream;
-  u2 index = 0; // index in the array with long/double occupying two slots
-  u4 i1 = *u1_index;
-  u4 i2 = *u2_index + 1;
-  for(int i = 0; i < array_length; i++) {
-    const u1 tag = u1_array[i1++] = cfs->get_u1(CHECK);
-    index++;
-    if (tag == ITEM_Long || tag == ITEM_Double) {
-      index++;
-    } else if (tag == ITEM_Object) {
-      const u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK);
-      guarantee_property(valid_klass_reference_at(class_index),
-                         "Bad class index %u in StackMap in class file %s",
-                         class_index, CHECK);
-    } else if (tag == ITEM_Uninitialized) {
-      const u2 offset = u2_array[i2++] = cfs->get_u2(CHECK);
-      guarantee_property(
-        offset < code_length,
-        "Bad uninitialized type offset %u in StackMap in class file %s",
-        offset, CHECK);
-    } else {
-      guarantee_property(
-        tag <= (u1)ITEM_Uninitialized,
-        "Unknown variable type %u in StackMap in class file %s",
-        tag, CHECK);
-    }
-  }
-  u2_array[*u2_index] = index;
-  *u1_index = i1;
-  *u2_index = i2;
-}
-
 static const u1* parse_stackmap_table(const ClassFileStream* const cfs,
                                       u4 code_attribute_length,
                                       bool need_verify,
--- a/src/hotspot/share/classfile/classFileParser.hpp	Fri Mar 08 16:21:16 2019 -0500
+++ b/src/hotspot/share/classfile/classFileParser.hpp	Fri Mar 08 23:02:06 2019 +0100
@@ -68,8 +68,7 @@
   //
   enum Publicity {
     INTERNAL,
-    BROADCAST,
-    NOF_PUBLICITY_LEVELS
+    BROADCAST
   };
 
   enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names
@@ -270,14 +269,6 @@
                                             u4 method_attribute_length,
                                             TRAPS);
 
-  void parse_type_array(u2 array_length,
-                        u4 code_length,
-                        u4* const u1_index,
-                        u4* const u2_index,
-                        u1* const u1_array,
-                        u2* const u2_array,
-                        TRAPS);
-
   // Classfile attribute parsing
   u2 parse_generic_signature_attribute(const ClassFileStream* const cfs, TRAPS);
   void parse_classfile_sourcefile_attribute(const ClassFileStream* const cfs, TRAPS);
@@ -524,7 +515,6 @@
   int itable_size() const { return _itable_size; }
 
   u2 this_class_index() const { return _this_class_index; }
-  u2 super_class_index() const { return _super_class_index; }
 
   bool is_unsafe_anonymous() const { return _unsafe_anonymous_host != NULL; }
   bool is_interface() const { return _access_flags.is_interface(); }
--- a/src/hotspot/share/classfile/classFileStream.cpp	Fri Mar 08 16:21:16 2019 -0500
+++ b/src/hotspot/share/classfile/classFileStream.cpp	Fri Mar 08 23:02:06 2019 +0100
@@ -30,7 +30,6 @@
 #include "memory/resourceArea.hpp"
 
 const bool ClassFileStream::verify = true;
-const bool ClassFileStream::no_verification = false;
 
 void ClassFileStream::truncated_file_error(TRAPS) const {
   THROW_MSG(vmSymbols::java_lang_ClassFormatError(), "Truncated class file");
@@ -73,69 +72,6 @@
                              need_verify());
 }
 
-u1 ClassFileStream::get_u1(TRAPS) const {
-  if (_need_verify) {
-    guarantee_more(1, CHECK_0);
-  } else {
-    assert(1 <= _buffer_end - _current, "buffer overflow");
-  }
-  return *_current++;
-}
-
-u2 ClassFileStream::get_u2(TRAPS) const {
-  if (_need_verify) {
-    guarantee_more(2, CHECK_0);
-  } else {
-    assert(2 <= _buffer_end - _current, "buffer overflow");
-  }
-  const u1* tmp = _current;
-  _current += 2;
-  return Bytes::get_Java_u2((address)tmp);
-}
-
-u4 ClassFileStream::get_u4(TRAPS) const {
-  if (_need_verify) {
-    guarantee_more(4, CHECK_0);
-  } else {
-    assert(4 <= _buffer_end - _current, "buffer overflow");
-  }
-  const u1* tmp = _current;
-  _current += 4;
-  return Bytes::get_Java_u4((address)tmp);
-}
-
-u8 ClassFileStream::get_u8(TRAPS) const {
-  if (_need_verify) {
-    guarantee_more(8, CHECK_0);
-  } else {
-    assert(8 <= _buffer_end - _current, "buffer overflow");
-  }
-  const u1* tmp = _current;
-  _current += 8;
-  return Bytes::get_Java_u8((address)tmp);
-}
-
-void ClassFileStream::skip_u1(int length, TRAPS) const {
-  if (_need_verify) {
-    guarantee_more(length, CHECK);
-  }
-  _current += length;
-}
-
-void ClassFileStream::skip_u2(int length, TRAPS) const {
-  if (_need_verify) {
-    guarantee_more(length * 2, CHECK);
-  }
-  _current += length * 2;
-}
-
-void ClassFileStream::skip_u4(int length, TRAPS) const {
-  if (_need_verify) {
-    guarantee_more(length * 4, CHECK);
-  }
-  _current += length * 4;
-}
-
 uint64_t ClassFileStream::compute_fingerprint() const {
   int classfile_size = length();
   int classfile_crc = ClassLoader::crc32(0, (const char*)buffer(), length());
--- a/src/hotspot/share/classfile/classFileStream.hpp	Fri Mar 08 16:21:16 2019 -0500
+++ b/src/hotspot/share/classfile/classFileStream.hpp	Fri Mar 08 23:02:06 2019 +0100
@@ -52,7 +52,6 @@
   const char* const clone_source() const;
 
  public:
-  static const bool no_verification;
   static const bool verify;
 
   ClassFileStream(const u1* buffer,
@@ -92,21 +91,34 @@
   }
 
   // Read u1 from stream
-  u1 get_u1(TRAPS) const;
   u1 get_u1_fast() const {
     return *_current++;
   }
+  u1 get_u1(TRAPS) const {
+    if (_need_verify) {
+      guarantee_more(1, CHECK_0);
+    } else {
+      assert(1 <= _buffer_end - _current, "buffer overflow");
+    }
+    return get_u1_fast();
+  }
 
   // Read u2 from stream
-  u2 get_u2(TRAPS) const;
   u2 get_u2_fast() const {
     u2 res = Bytes::get_Java_u2((address)_current);
     _current += 2;
     return res;
   }
+  u2 get_u2(TRAPS) const {
+    if (_need_verify) {
+      guarantee_more(2, CHECK_0);
+    } else {
+      assert(2 <= _buffer_end - _current, "buffer overflow");
+    }
+    return get_u2_fast();
+  }
 
   // Read u4 from stream
-  u4 get_u4(TRAPS) const;
   u4 get_u4_fast() const {
     u4 res = Bytes::get_Java_u4((address)_current);
     _current += 4;
@@ -114,25 +126,27 @@
   }
 
   // Read u8 from stream
-  u8 get_u8(TRAPS) const;
   u8 get_u8_fast() const {
     u8 res = Bytes::get_Java_u8((address)_current);
     _current += 8;
     return res;
   }
 
-  // Skip length u1 or u2 elements from stream
-  void skip_u1(int length, TRAPS) const;
+  // Skip length elements from stream
+  void skip_u1(int length, TRAPS) const {
+    if (_need_verify) {
+      guarantee_more(length, CHECK);
+    }
+    skip_u1_fast(length);
+  }
   void skip_u1_fast(int length) const {
     _current += length;
   }
 
-  void skip_u2(int length, TRAPS) const;
   void skip_u2_fast(int length) const {
     _current += 2 * length;
   }
 
-  void skip_u4(int length, TRAPS) const;
   void skip_u4_fast(int length) const {
     _current += 4 * length;
   }
--- a/src/hotspot/share/code/compressedStream.cpp	Fri Mar 08 16:21:16 2019 -0500
+++ b/src/hotspot/share/code/compressedStream.cpp	Fri Mar 08 23:02:06 2019 +0100
@@ -26,15 +26,6 @@
 #include "code/compressedStream.hpp"
 #include "utilities/ostream.hpp"
 
-// 32-bit one-to-one sign encoding taken from Pack200
-// converts leading sign bits into leading zeroes with trailing sign bit
-inline juint CompressedStream::encode_sign(jint  value) {
-  return (value << 1) ^ (value >> 31);
-}
-inline jint  CompressedStream::decode_sign(juint value) {
-  return (value >> 1) ^ -(jint)(value & 1);
-}
-
 // 32-bit self-inverse encoding of float bits
 // converts trailing zeroes (common in floats) to leading zeroes
 inline juint CompressedStream::reverse_int(juint i) {
@@ -46,7 +37,6 @@
   return i;
 }
 
-
 jint CompressedReadStream::read_signed_int() {
   return decode_sign(read_int());
 }
@@ -90,11 +80,6 @@
   _size   = _size * 2;
 }
 
-void CompressedWriteStream::write_signed_int(jint value) {
-  // this encoding, called SIGNED5, is taken from Pack200
-  write_int(encode_sign(value));
-}
-
 void CompressedWriteStream::write_float(jfloat value) {
   juint f = jint_cast(value);
   juint rf = reverse_int(f);
@@ -117,136 +102,3 @@
   write_signed_int(low(value));
   write_signed_int(high(value));
 }
-
-
-/// The remaining details
-
-#ifndef PRODUCT
-// set this to trigger unit test
-void test_compressed_stream(int trace);
-bool test_compressed_stream_enabled = false;
-#endif
-
-void CompressedWriteStream::write_int_mb(jint value) {
-  debug_only(int pos1 = position());
-  juint sum = value;
-  for (int i = 0; ; ) {
-    if (sum < L || i == MAX_i) {
-      // remainder is either a "low code" or the 5th byte
-      assert(sum == (u_char)sum, "valid byte");
-      write((u_char)sum);
-      break;
-    }
-    sum -= L;
-    int b_i = L + (sum % H);  // this is a "high code"
-    sum >>= lg_H;             // extracted 6 bits
-    write(b_i); ++i;
-  }
-
-#ifndef PRODUCT
-  if (test_compressed_stream_enabled) {  // hack to enable this stress test
-    test_compressed_stream_enabled = false;
-    test_compressed_stream(0);
-  }
-#endif
-}
-
-
-#ifndef PRODUCT
-/// a unit test (can be run by hand from a debugger)
-
-// Avoid a VS2005 compiler stack overflow w/ fastdebug build.
-// The following pragma optimize turns off optimization ONLY
-// for this block (a matching directive turns it back on later).
-// These directives can be removed once the MS VS.NET 2005
-// compiler stack overflow is fixed.
-#if defined(_MSC_VER) && _MSC_VER >=1400 && !defined(_WIN64)
-#pragma optimize("", off)
-#pragma warning(disable: 4748)
-#endif
-
-// generator for an "interesting" set of critical values
-enum { stretch_limit = (1<<16) * (64-16+1) };
-static jlong stretch(jint x, int bits) {
-  // put x[high 4] into place
-  jlong h = (jlong)((x >> (16-4))) << (bits - 4);
-  // put x[low 12] into place, sign extended
-  jlong l = ((jlong)x << (64-12)) >> (64-12);
-  // move l upwards, maybe
-  l <<= (x >> 16);
-  return h ^ l;
-}
-
-PRAGMA_DIAG_PUSH
-PRAGMA_FORMAT_IGNORED // Someone needs to deal with this.
-void test_compressed_stream(int trace) {
-  CompressedWriteStream bytes(stretch_limit * 100);
-  jint n;
-  int step = 0, fails = 0;
-#define CHECKXY(x, y, fmt) { \
-    ++step; \
-    int xlen = (pos = decode.position()) - lastpos; lastpos = pos; \
-    if (trace > 0 && (step % trace) == 0) { \
-      tty->print_cr("step %d, n=%08x: value=" fmt " (len=%d)", \
-                    step, n, x, xlen); } \
-    if (x != y) {                                                     \
-      tty->print_cr("step %d, n=%d: " fmt " != " fmt, step, n, x, y); \
-      fails++; \
-    } }
-  for (n = 0; n < (1<<8); n++) {
-    jbyte x = (jbyte)n;
-    bytes.write_byte(x); ++step;
-  }
-  for (n = 0; n < stretch_limit; n++) {
-    jint x = (jint)stretch(n, 32);
-    bytes.write_int(x); ++step;
-    bytes.write_signed_int(x); ++step;
-    bytes.write_float(jfloat_cast(x)); ++step;
-  }
-  for (n = 0; n < stretch_limit; n++) {
-    jlong x = stretch(n, 64);
-    bytes.write_long(x); ++step;
-    bytes.write_double(jdouble_cast(x)); ++step;
-  }
-  int length = bytes.position();
-  if (trace != 0)
-    tty->print_cr("set up test of %d stream values, size %d", step, length);
-  step = 0;
-  // now decode it all
-  CompressedReadStream decode(bytes.buffer());
-  int pos, lastpos = decode.position();
-  for (n = 0; n < (1<<8); n++) {
-    jbyte x = (jbyte)n;
-    jbyte y = decode.read_byte();
-    CHECKXY(x, y, "%db");
-  }
-  for (n = 0; n < stretch_limit; n++) {
-    jint x = (jint)stretch(n, 32);
-    jint y1 = decode.read_int();
-    CHECKXY(x, y1, "%du");
-    jint y2 = decode.read_signed_int();
-    CHECKXY(x, y2, "%di");
-    jint y3 = jint_cast(decode.read_float());
-    CHECKXY(x, y3, "%df");
-  }
-  for (n = 0; n < stretch_limit; n++) {
-    jlong x = stretch(n, 64);
-    jlong y1 = decode.read_long();
-    CHECKXY(x, y1, INT64_FORMAT "l");
-    jlong y2 = jlong_cast(decode.read_double());
-    CHECKXY(x, y2, INT64_FORMAT "d");
-  }
-  int length2 = decode.position();
-  if (trace != 0)
-    tty->print_cr("finished test of %d stream values, size %d", step, length2);
-  guarantee(length == length2, "bad length");
-  guarantee(fails == 0, "test failures");
-}
-PRAGMA_DIAG_POP
-
-#if defined(_MSC_VER) &&_MSC_VER >=1400 && !defined(_WIN64)
-#pragma warning(default: 4748)
-#pragma optimize("", on)
-#endif
-
-#endif // PRODUCT
--- a/src/hotspot/share/code/compressedStream.hpp	Fri Mar 08 16:21:16 2019 -0500
+++ b/src/hotspot/share/code/compressedStream.hpp	Fri Mar 08 23:02:06 2019 +0100
@@ -43,11 +43,11 @@
     MAX_i = 4                 // bytes are numbered in (0..4), max 5 bytes
   };
 
-  // these inlines are defined only in compressedStream.cpp
-  static inline juint encode_sign(jint  value);  // for Pack200 SIGNED5
-  static inline jint  decode_sign(juint value);  // for Pack200 SIGNED5
-  static inline juint reverse_int(juint bits);   // to trim trailing float 0's
-
+  // 32-bit one-to-one sign encoding taken from Pack200
+  // converts leading sign bits into leading zeroes with trailing sign bit
+  static juint encode_sign(jint  value) { return (value << 1) ^ (value >> 31); }
+  static jint  decode_sign(juint value) { return (value >> 1) ^ -(jint)(value & 1); }
+  static juint reverse_int(juint i);   // to trim trailing float 0's
  public:
   CompressedStream(u_char* buffer, int position = 0) {
     _buffer   = buffer;
@@ -134,7 +134,22 @@
   }
   void grow();
 
-  void write_int_mb(jint value);  // UNSIGNED5 coding, 1-5 byte cases
+  // UNSIGNED5 coding, 1-5 byte cases
+  void write_int_mb(jint value) {
+    juint sum = value;
+    for (int i = 0; ; ) {
+      if (sum < L || i == MAX_i) {
+        // remainder is either a "low code" or the 5th byte
+        assert(sum == (u_char)sum, "valid byte");
+        write((u_char)sum);
+        break;
+      }
+      sum -= L;
+      int b_i = L + (sum % H);  // this is a "high code"
+      sum >>= lg_H;             // extracted 6 bits
+      write(b_i); ++i;
+    }
+  }
 
  protected:
   int _size;
@@ -151,7 +166,7 @@
   void write_int(jint value)           { if ((juint)value < L && !full())
                                                store((u_char)value);
                                          else  write_int_mb(value);  }
-  void write_signed_int(jint value);   // write_int(encode_sign(value))
+  void write_signed_int(jint value)    { write_int(encode_sign(value)); }
   void write_float(jfloat value);      // write_int(reverse_int(jint_cast(v)))
   void write_double(jdouble value);    // write_int(reverse_int(<low,high>))
   void write_long(jlong value);        // write_signed_int(<low,high>)
--- a/src/hotspot/share/oops/method.cpp	Fri Mar 08 16:21:16 2019 -0500
+++ b/src/hotspot/share/oops/method.cpp	Fri Mar 08 23:02:06 2019 +0100
@@ -1684,35 +1684,11 @@
   while (s.next() >= 0) BytecodeTracer::trace(mh, s.bcp(), st);
 }
 
-
-// Simple compression of line number tables. We use a regular compressed stream, except that we compress deltas
-// between (bci,line) pairs since they are smaller. If (bci delta, line delta) fits in (5-bit unsigned, 3-bit unsigned)
-// we save it as one byte, otherwise we write a 0xFF escape character and use regular compression. 0x0 is used
-// as end-of-stream terminator.
-
-void CompressedLineNumberWriteStream::write_pair_regular(int bci_delta, int line_delta) {
-  // bci and line number does not compress into single byte.
-  // Write out escape character and use regular compression for bci and line number.
-  write_byte((jubyte)0xFF);
-  write_signed_int(bci_delta);
-  write_signed_int(line_delta);
-}
-
-// See comment in method.hpp which explains why this exists.
-#if defined(_M_AMD64) && _MSC_VER >= 1400
-#pragma optimize("", off)
-void CompressedLineNumberWriteStream::write_pair(int bci, int line) {
-  write_pair_inline(bci, line);
-}
-#pragma optimize("", on)
-#endif
-
 CompressedLineNumberReadStream::CompressedLineNumberReadStream(u_char* buffer) : CompressedReadStream(buffer) {
   _bci = 0;
   _line = 0;
 };
 
-
 bool CompressedLineNumberReadStream::read_pair() {
   jubyte next = read_byte();
   // Check for terminator
--- a/src/hotspot/share/oops/method.hpp	Fri Mar 08 16:21:16 2019 -0500
+++ b/src/hotspot/share/oops/method.hpp	Fri Mar 08 23:02:06 2019 +0100
@@ -1022,36 +1022,12 @@
   // Write (bci, line number) pair to stream
   void write_pair_regular(int bci_delta, int line_delta);
 
-  inline void write_pair_inline(int bci, int line) {
-    int bci_delta = bci - _bci;
-    int line_delta = line - _line;
-    _bci = bci;
-    _line = line;
-    // Skip (0,0) deltas - they do not add information and conflict with terminator.
-    if (bci_delta == 0 && line_delta == 0) return;
-    // Check if bci is 5-bit and line number 3-bit unsigned.
-    if (((bci_delta & ~0x1F) == 0) && ((line_delta & ~0x7) == 0)) {
-      // Compress into single byte.
-      jubyte value = ((jubyte) bci_delta << 3) | (jubyte) line_delta;
-      // Check that value doesn't match escape character.
-      if (value != 0xFF) {
-        write_byte(value);
-        return;
-      }
-    }
-    write_pair_regular(bci_delta, line_delta);
-  }
+  // If (bci delta, line delta) fits in (5-bit unsigned, 3-bit unsigned)
+  // we save it as one byte, otherwise we write a 0xFF escape character
+  // and use regular compression. 0x0 is used as end-of-stream terminator.
+  void write_pair_inline(int bci, int line);
 
-// Windows AMD64 + Apr 2005 PSDK with /O2 generates bad code for write_pair.
-// Disabling optimization doesn't work for methods in header files
-// so we force it to call through the non-optimized version in the .cpp.
-// It's gross, but it's the only way we can ensure that all callers are
-// fixed.  _MSC_VER is defined by the windows compiler
-#if defined(_M_AMD64) && _MSC_VER >= 1400
   void write_pair(int bci, int line);
-#else
-  void write_pair(int bci, int line) { write_pair_inline(bci, line); }
-#endif
 
   // Write end-of-stream marker
   void write_terminator()                        { write_byte(0); }
--- a/src/hotspot/share/oops/method.inline.hpp	Fri Mar 08 16:21:16 2019 -0500
+++ b/src/hotspot/share/oops/method.inline.hpp	Fri Mar 08 23:02:06 2019 +0100
@@ -48,6 +48,39 @@
   return OrderAccess::load_acquire(&_code);
 }
 
+// Write (bci, line number) pair to stream
+inline void CompressedLineNumberWriteStream::write_pair_regular(int bci_delta, int line_delta) {
+  // bci and line number does not compress into single byte.
+  // Write out escape character and use regular compression for bci and line number.
+  write_byte((jubyte)0xFF);
+  write_signed_int(bci_delta);
+  write_signed_int(line_delta);
+}
+
+inline void CompressedLineNumberWriteStream::write_pair_inline(int bci, int line) {
+  int bci_delta = bci - _bci;
+  int line_delta = line - _line;
+  _bci = bci;
+  _line = line;
+  // Skip (0,0) deltas - they do not add information and conflict with terminator.
+  if (bci_delta == 0 && line_delta == 0) return;
+  // Check if bci is 5-bit and line number 3-bit unsigned.
+  if (((bci_delta & ~0x1F) == 0) && ((line_delta & ~0x7) == 0)) {
+    // Compress into single byte.
+    jubyte value = ((jubyte) bci_delta << 3) | (jubyte) line_delta;
+    // Check that value doesn't match escape character.
+    if (value != 0xFF) {
+      write_byte(value);
+      return;
+    }
+  }
+  write_pair_regular(bci_delta, line_delta);
+}
+
+inline void CompressedLineNumberWriteStream::write_pair(int bci, int line) {
+  write_pair_inline(bci, line);
+}
+
 inline bool Method::has_compiled_code() const { return code() != NULL; }
 
 #endif // SHARE_OOPS_METHOD_INLINE_HPP
--- a/src/hotspot/share/runtime/relocator.cpp	Fri Mar 08 16:21:16 2019 -0500
+++ b/src/hotspot/share/runtime/relocator.cpp	Fri Mar 08 23:02:06 2019 +0100
@@ -28,6 +28,7 @@
 #include "memory/metadataFactory.hpp"
 #include "memory/oopFactory.hpp"
 #include "memory/universe.hpp"
+#include "oops/method.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/relocator.hpp"