changeset 56541:a38132298eda

8223320: [AOT] jck test api/javax_script/ScriptEngine/PutGet.html fails when test classes are AOTed Summary: Materialization of primitive boxes should use caches Reviewed-by: kvn, never
author iveresov
date Mon, 03 Jun 2019 13:21:02 -0700
parents d3e404cc3972
children a8ee59471f55
files src/hotspot/share/aot/aotLoader.cpp src/hotspot/share/aot/aotLoader.hpp src/hotspot/share/classfile/javaClasses.cpp src/hotspot/share/classfile/javaClasses.hpp src/hotspot/share/classfile/vmSymbols.hpp src/hotspot/share/code/debugInfo.cpp src/hotspot/share/code/debugInfo.hpp src/hotspot/share/jvmci/jvmciCodeInstaller.cpp src/hotspot/share/jvmci/jvmciCompilerToVM.cpp src/hotspot/share/jvmci/jvmciJavaClasses.hpp src/hotspot/share/runtime/deoptimization.cpp src/hotspot/share/runtime/deoptimization.hpp src/hotspot/share/runtime/thread.cpp src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/BoxDeoptimizationTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java
diffstat 18 files changed, 666 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/aot/aotLoader.cpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/aot/aotLoader.cpp	Mon Jun 03 13:21:02 2019 -0700
@@ -319,3 +319,24 @@
   vmassert(success || thread->last_frame().sender(&map).is_deoptimized_frame(), "caller not deoptimized on failure");
   return success;
 }
+
+
+// This should be called very early during startup before any of the AOTed methods that use boxes can deoptimize.
+// Deoptimization machinery expects the caches to be present and populated.
+void AOTLoader::initialize_box_caches(TRAPS) {
+  if (!UseAOT || libraries_count() == 0) {
+    return;
+  }
+  TraceTime timer("AOT initialization of box caches", TRACETIME_LOG(Info, aot, startuptime));
+  Symbol* box_classes[] = { java_lang_Boolean::symbol(), java_lang_Byte_ByteCache::symbol(),
+    java_lang_Short_ShortCache::symbol(), java_lang_Character_CharacterCache::symbol(),
+    java_lang_Integer_IntegerCache::symbol(), java_lang_Long_LongCache::symbol() };
+
+  for (unsigned i = 0; i < sizeof(box_classes) / sizeof(Symbol*); i++) {
+    Klass* k = SystemDictionary::resolve_or_fail(box_classes[i], true, CHECK);
+    InstanceKlass* ik = InstanceKlass::cast(k);
+    if (ik->is_not_initialized()) {
+      ik->initialize(CHECK);
+    }
+  }
+}
--- a/src/hotspot/share/aot/aotLoader.hpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/aot/aotLoader.hpp	Mon Jun 03 13:21:02 2019 -0700
@@ -64,6 +64,7 @@
   static void oops_do(OopClosure* f) NOT_AOT_RETURN;
   static void metadata_do(MetadataClosure* f) NOT_AOT_RETURN;
   static void mark_evol_dependent_methods(InstanceKlass* dependee) NOT_AOT_RETURN;
+  static void initialize_box_caches(TRAPS) NOT_AOT_RETURN;
 
   NOT_PRODUCT( static void print_statistics() NOT_AOT_RETURN; )
 
--- a/src/hotspot/share/classfile/javaClasses.cpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Mon Jun 03 13:21:02 2019 -0700
@@ -4155,6 +4155,14 @@
 int java_util_concurrent_locks_AbstractOwnableSynchronizer::_owner_offset;
 int reflect_ConstantPool::_oop_offset;
 int reflect_UnsafeStaticFieldAccessorImpl::_base_offset;
+int java_lang_Integer_IntegerCache::_static_cache_offset;
+int java_lang_Long_LongCache::_static_cache_offset;
+int java_lang_Character_CharacterCache::_static_cache_offset;
+int java_lang_Short_ShortCache::_static_cache_offset;
+int java_lang_Byte_ByteCache::_static_cache_offset;
+int java_lang_Boolean::_static_TRUE_offset;
+int java_lang_Boolean::_static_FALSE_offset;
+
 
 
 #define STACKTRACEELEMENT_FIELDS_DO(macro) \
@@ -4314,6 +4322,192 @@
 }
 #endif
 
+#define INTEGER_CACHE_FIELDS_DO(macro) \
+  macro(_static_cache_offset, k, "cache", java_lang_Integer_array_signature, true)
+
+void java_lang_Integer_IntegerCache::compute_offsets(InstanceKlass *k) {
+  guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
+  INTEGER_CACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+objArrayOop java_lang_Integer_IntegerCache::cache(InstanceKlass *ik) {
+  oop base = ik->static_field_base_raw();
+  return objArrayOop(base->obj_field(_static_cache_offset));
+}
+
+Symbol* java_lang_Integer_IntegerCache::symbol() {
+  return vmSymbols::java_lang_Integer_IntegerCache();
+}
+
+#if INCLUDE_CDS
+void java_lang_Integer_IntegerCache::serialize_offsets(SerializeClosure* f) {
+  INTEGER_CACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+#undef INTEGER_CACHE_FIELDS_DO
+
+jint java_lang_Integer::value(oop obj) {
+   jvalue v;
+   java_lang_boxing_object::get_value(obj, &v);
+   return v.i;
+}
+
+#define LONG_CACHE_FIELDS_DO(macro) \
+  macro(_static_cache_offset, k, "cache", java_lang_Long_array_signature, true)
+
+void java_lang_Long_LongCache::compute_offsets(InstanceKlass *k) {
+  guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
+  LONG_CACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+objArrayOop java_lang_Long_LongCache::cache(InstanceKlass *ik) {
+  oop base = ik->static_field_base_raw();
+  return objArrayOop(base->obj_field(_static_cache_offset));
+}
+
+Symbol* java_lang_Long_LongCache::symbol() {
+  return vmSymbols::java_lang_Long_LongCache();
+}
+
+#if INCLUDE_CDS
+void java_lang_Long_LongCache::serialize_offsets(SerializeClosure* f) {
+  LONG_CACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+#undef LONG_CACHE_FIELDS_DO
+
+jlong java_lang_Long::value(oop obj) {
+   jvalue v;
+   java_lang_boxing_object::get_value(obj, &v);
+   return v.j;
+}
+
+#define CHARACTER_CACHE_FIELDS_DO(macro) \
+  macro(_static_cache_offset, k, "cache", java_lang_Character_array_signature, true)
+
+void java_lang_Character_CharacterCache::compute_offsets(InstanceKlass *k) {
+  guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
+  CHARACTER_CACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+objArrayOop java_lang_Character_CharacterCache::cache(InstanceKlass *ik) {
+  oop base = ik->static_field_base_raw();
+  return objArrayOop(base->obj_field(_static_cache_offset));
+}
+
+Symbol* java_lang_Character_CharacterCache::symbol() {
+  return vmSymbols::java_lang_Character_CharacterCache();
+}
+
+#if INCLUDE_CDS
+void java_lang_Character_CharacterCache::serialize_offsets(SerializeClosure* f) {
+  CHARACTER_CACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+#undef CHARACTER_CACHE_FIELDS_DO
+
+jchar java_lang_Character::value(oop obj) {
+   jvalue v;
+   java_lang_boxing_object::get_value(obj, &v);
+   return v.c;
+}
+
+#define SHORT_CACHE_FIELDS_DO(macro) \
+  macro(_static_cache_offset, k, "cache", java_lang_Short_array_signature, true)
+
+void java_lang_Short_ShortCache::compute_offsets(InstanceKlass *k) {
+  guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
+  SHORT_CACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+objArrayOop java_lang_Short_ShortCache::cache(InstanceKlass *ik) {
+  oop base = ik->static_field_base_raw();
+  return objArrayOop(base->obj_field(_static_cache_offset));
+}
+
+Symbol* java_lang_Short_ShortCache::symbol() {
+  return vmSymbols::java_lang_Short_ShortCache();
+}
+
+#if INCLUDE_CDS
+void java_lang_Short_ShortCache::serialize_offsets(SerializeClosure* f) {
+  SHORT_CACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+#undef SHORT_CACHE_FIELDS_DO
+
+jshort java_lang_Short::value(oop obj) {
+   jvalue v;
+   java_lang_boxing_object::get_value(obj, &v);
+   return v.s;
+}
+
+#define BYTE_CACHE_FIELDS_DO(macro) \
+  macro(_static_cache_offset, k, "cache", java_lang_Byte_array_signature, true)
+
+void java_lang_Byte_ByteCache::compute_offsets(InstanceKlass *k) {
+  guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
+  BYTE_CACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+objArrayOop java_lang_Byte_ByteCache::cache(InstanceKlass *ik) {
+  oop base = ik->static_field_base_raw();
+  return objArrayOop(base->obj_field(_static_cache_offset));
+}
+
+Symbol* java_lang_Byte_ByteCache::symbol() {
+  return vmSymbols::java_lang_Byte_ByteCache();
+}
+
+#if INCLUDE_CDS
+void java_lang_Byte_ByteCache::serialize_offsets(SerializeClosure* f) {
+  BYTE_CACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+#undef BYTE_CACHE_FIELDS_DO
+
+jbyte java_lang_Byte::value(oop obj) {
+   jvalue v;
+   java_lang_boxing_object::get_value(obj, &v);
+   return v.b;
+}
+#define BOOLEAN_FIELDS_DO(macro) \
+  macro(_static_TRUE_offset, k, "TRUE", java_lang_Boolean_signature, true); \
+  macro(_static_FALSE_offset, k, "FALSE", java_lang_Boolean_signature, true)
+
+
+void java_lang_Boolean::compute_offsets(InstanceKlass *k) {
+  guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
+  BOOLEAN_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+oop java_lang_Boolean::get_TRUE(InstanceKlass *ik) {
+  oop base = ik->static_field_base_raw();
+  return base->obj_field(_static_TRUE_offset);
+}
+
+oop java_lang_Boolean::get_FALSE(InstanceKlass *ik) {
+  oop base = ik->static_field_base_raw();
+  return base->obj_field(_static_FALSE_offset);
+}
+
+Symbol* java_lang_Boolean::symbol() {
+  return vmSymbols::java_lang_Boolean();
+}
+
+#if INCLUDE_CDS
+void java_lang_Boolean::serialize_offsets(SerializeClosure* f) {
+  BOOLEAN_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+#undef BOOLEAN_CACHE_FIELDS_DO
+
+jboolean java_lang_Boolean::value(oop obj) {
+   jvalue v;
+   java_lang_boxing_object::get_value(obj, &v);
+   return v.z;
+}
+
 static int member_offset(int hardcoded_offset) {
   return (hardcoded_offset * heapOopSize) + instanceOopDesc::base_offset_in_bytes();
 }
--- a/src/hotspot/share/classfile/javaClasses.hpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Mon Jun 03 13:21:02 2019 -0700
@@ -1497,6 +1497,94 @@
   static void serialize_offsets(SerializeClosure* f) { }
 };
 
+class java_lang_Integer : AllStatic {
+public:
+  static jint value(oop obj);
+};
+
+class java_lang_Long : AllStatic {
+public:
+  static jlong value(oop obj);
+};
+
+class java_lang_Character : AllStatic {
+public:
+  static jchar value(oop obj);
+};
+
+class java_lang_Short : AllStatic {
+public:
+  static jshort value(oop obj);
+};
+
+class java_lang_Byte : AllStatic {
+public:
+  static jbyte value(oop obj);
+};
+
+class java_lang_Boolean : AllStatic {
+ private:
+  static int _static_TRUE_offset;
+  static int _static_FALSE_offset;
+ public:
+  static Symbol* symbol();
+  static void compute_offsets(InstanceKlass* k);
+  static oop  get_TRUE(InstanceKlass *k);
+  static oop  get_FALSE(InstanceKlass *k);
+  static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
+  static jboolean value(oop obj);
+};
+
+class java_lang_Integer_IntegerCache : AllStatic {
+ private:
+  static int _static_cache_offset;
+ public:
+  static Symbol* symbol();
+  static void compute_offsets(InstanceKlass* k);
+  static objArrayOop  cache(InstanceKlass *k);
+  static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
+};
+
+class java_lang_Long_LongCache : AllStatic {
+ private:
+  static int _static_cache_offset;
+ public:
+  static Symbol* symbol();
+  static void compute_offsets(InstanceKlass* k);
+  static objArrayOop  cache(InstanceKlass *k);
+  static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
+};
+
+class java_lang_Character_CharacterCache : AllStatic {
+ private:
+  static int _static_cache_offset;
+ public:
+  static Symbol* symbol();
+  static void compute_offsets(InstanceKlass* k);
+  static objArrayOop  cache(InstanceKlass *k);
+  static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
+};
+
+class java_lang_Short_ShortCache : AllStatic {
+ private:
+  static int _static_cache_offset;
+ public:
+  static Symbol* symbol();
+  static void compute_offsets(InstanceKlass* k);
+  static objArrayOop  cache(InstanceKlass *k);
+  static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
+};
+
+class java_lang_Byte_ByteCache : AllStatic {
+ private:
+  static int _static_cache_offset;
+ public:
+  static Symbol* symbol();
+  static void compute_offsets(InstanceKlass* k);
+  static objArrayOop  cache(InstanceKlass *k);
+  static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
+};
+
 // Use to declare fields that need to be injected into Java classes
 // for the JVM to use.  The name_index and signature_index are
 // declared in vmSymbols.  The may_be_java flag is used to declare
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Mon Jun 03 13:21:02 2019 -0700
@@ -442,6 +442,11 @@
   template(getProtectionDomain_name,                  "getProtectionDomain")                      \
   template(getProtectionDomain_signature,             "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \
   template(java_lang_Integer_array_signature,         "[Ljava/lang/Integer;")                     \
+  template(java_lang_Long_array_signature,            "[Ljava/lang/Long;")                        \
+  template(java_lang_Character_array_signature,       "[Ljava/lang/Character;")                   \
+  template(java_lang_Short_array_signature,           "[Ljava/lang/Short;")                       \
+  template(java_lang_Byte_array_signature,            "[Ljava/lang/Byte;")                        \
+  template(java_lang_Boolean_signature,               "Ljava/lang/Boolean;")                      \
   template(url_code_signer_array_void_signature,      "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \
   template(module_entry_name,                         "module_entry")                             \
   template(resolved_references_name,                  "<resolved_references>")                    \
--- a/src/hotspot/share/code/debugInfo.cpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/code/debugInfo.cpp	Mon Jun 03 13:21:02 2019 -0700
@@ -56,7 +56,7 @@
   return o;
 }
 
-ScopeValue* DebugInfoReadStream::read_object_value() {
+ScopeValue* DebugInfoReadStream::read_object_value(bool is_auto_box) {
   int id = read_int();
 #ifdef ASSERT
   assert(_obj_pool != NULL, "object pool does not exist");
@@ -64,7 +64,7 @@
     assert(_obj_pool->at(i)->as_ObjectValue()->id() != id, "should not be read twice");
   }
 #endif
-  ObjectValue* result = new ObjectValue(id);
+  ObjectValue* result = is_auto_box ? new AutoBoxObjectValue(id) : new ObjectValue(id);
   // Cache the object since an object field could reference it.
   _obj_pool->push(result);
   result->read_object(this);
@@ -88,18 +88,20 @@
 
 enum { LOCATION_CODE = 0, CONSTANT_INT_CODE = 1,  CONSTANT_OOP_CODE = 2,
                           CONSTANT_LONG_CODE = 3, CONSTANT_DOUBLE_CODE = 4,
-                          OBJECT_CODE = 5,        OBJECT_ID_CODE = 6 };
+                          OBJECT_CODE = 5,        OBJECT_ID_CODE = 6,
+                          AUTO_BOX_OBJECT_CODE = 7 };
 
 ScopeValue* ScopeValue::read_from(DebugInfoReadStream* stream) {
   ScopeValue* result = NULL;
   switch(stream->read_int()) {
-   case LOCATION_CODE:        result = new LocationValue(stream);        break;
-   case CONSTANT_INT_CODE:    result = new ConstantIntValue(stream);     break;
-   case CONSTANT_OOP_CODE:    result = new ConstantOopReadValue(stream); break;
-   case CONSTANT_LONG_CODE:   result = new ConstantLongValue(stream);    break;
-   case CONSTANT_DOUBLE_CODE: result = new ConstantDoubleValue(stream);  break;
-   case OBJECT_CODE:          result = stream->read_object_value();      break;
-   case OBJECT_ID_CODE:       result = stream->get_cached_object();      break;
+   case LOCATION_CODE:        result = new LocationValue(stream);                        break;
+   case CONSTANT_INT_CODE:    result = new ConstantIntValue(stream);                     break;
+   case CONSTANT_OOP_CODE:    result = new ConstantOopReadValue(stream);                 break;
+   case CONSTANT_LONG_CODE:   result = new ConstantLongValue(stream);                    break;
+   case CONSTANT_DOUBLE_CODE: result = new ConstantDoubleValue(stream);                  break;
+   case OBJECT_CODE:          result = stream->read_object_value(false /*is_auto_box*/); break;
+   case AUTO_BOX_OBJECT_CODE: result = stream->read_object_value(true /*is_auto_box*/);  break;
+   case OBJECT_ID_CODE:       result = stream->get_cached_object();                      break;
    default: ShouldNotReachHere();
   }
   return result;
@@ -142,7 +144,7 @@
     stream->write_int(_id);
   } else {
     _visited = true;
-    stream->write_int(OBJECT_CODE);
+    stream->write_int(is_auto_box() ? AUTO_BOX_OBJECT_CODE : OBJECT_CODE);
     stream->write_int(_id);
     _klass->write_on(stream);
     int length = _field_values.length();
@@ -154,7 +156,7 @@
 }
 
 void ObjectValue::print_on(outputStream* st) const {
-  st->print("obj[%d]", _id);
+  st->print("%s[%d]", is_auto_box() ? "box_obj" : "obj", _id);
 }
 
 void ObjectValue::print_fields_on(outputStream* st) const {
--- a/src/hotspot/share/code/debugInfo.hpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/code/debugInfo.hpp	Mon Jun 03 13:21:02 2019 -0700
@@ -49,6 +49,7 @@
   // Testers
   virtual bool is_location() const { return false; }
   virtual bool is_object() const { return false; }
+  virtual bool is_auto_box() const { return false; }
   virtual bool is_constant_int() const { return false; }
   virtual bool is_constant_double() const { return false; }
   virtual bool is_constant_long() const { return false; }
@@ -94,13 +95,12 @@
 // An ObjectValue describes an object eliminated by escape analysis.
 
 class ObjectValue: public ScopeValue {
- private:
+ protected:
   int                        _id;
   ScopeValue*                _klass;
   GrowableArray<ScopeValue*> _field_values;
   Handle                     _value;
   bool                       _visited;
-
  public:
   ObjectValue(int id, ScopeValue* klass)
      : _id(id)
@@ -140,6 +140,16 @@
   void print_fields_on(outputStream* st) const;
 };
 
+class AutoBoxObjectValue : public ObjectValue {
+  bool                       _cached;
+public:
+  bool                       is_auto_box() const        { return true; }
+  bool                       is_cached() const          { return _cached; }
+  void                       set_cached(bool cached)    { _cached = cached; }
+  AutoBoxObjectValue(int id, ScopeValue* klass) : ObjectValue(id, klass), _cached(false) { }
+  AutoBoxObjectValue(int id) : ObjectValue(id), _cached(false) { }
+};
+
 
 // A ConstantIntValue describes a constant int; i.e., the corresponding logical entity
 // is either a source constant or its computation has been constant-folded.
@@ -280,7 +290,7 @@
     assert(o == NULL || o->is_metadata(), "meta data only");
     return o;
   }
-  ScopeValue* read_object_value();
+  ScopeValue* read_object_value(bool is_auto_box);
   ScopeValue* get_cached_object();
   // BCI encoding is mostly unsigned, but -1 is a distinguished value
   int read_bci() { return read_int() + InvocationEntryBci; }
--- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp	Mon Jun 03 13:21:02 2019 -0700
@@ -988,9 +988,11 @@
     JVMCIObject value = JVMCIENV->get_object_at(virtualObjects, i);
     int id = jvmci_env()->get_VirtualObject_id(value);
     JVMCIObject type = jvmci_env()->get_VirtualObject_type(value);
+    bool is_auto_box = jvmci_env()->get_VirtualObject_isAutoBox(value);
     Klass* klass = jvmci_env()->asKlass(type);
     oop javaMirror = klass->java_mirror();
-    ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror)));
+    ScopeValue *klass_sv = new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror));
+    ObjectValue* sv = is_auto_box ? new AutoBoxObjectValue(id, klass_sv) : new ObjectValue(id, klass_sv);
     if (id < 0 || id >= objects->length()) {
       JVMCI_ERROR_NULL("virtual object id %d out of bounds", id);
     }
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Mon Jun 03 13:21:02 2019 -0700
@@ -1213,7 +1213,7 @@
                   }
                 }
               }
-              bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), objects, CHECK_NULL);
+              bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), fst.register_map(), objects, CHECK_NULL);
               Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects, realloc_failures, false);
               realloc_called = true;
 
@@ -1471,7 +1471,7 @@
     return;
   }
 
-  bool realloc_failures = Deoptimization::realloc_objects(thread, fstAfterDeopt.current(), objects, CHECK);
+  bool realloc_failures = Deoptimization::realloc_objects(thread, fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, CHECK);
   Deoptimization::reassign_fields(fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, realloc_failures, false);
 
   for (int frame_index = 0; frame_index < virtualFrames->length(); frame_index++) {
--- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp	Mon Jun 03 13:21:02 2019 -0700
@@ -309,6 +309,7 @@
   end_class                                                                                                   \
   start_class(VirtualObject, jdk_vm_ci_code_VirtualObject)                                                    \
     int_field(VirtualObject, id)                                                                              \
+    boolean_field(VirtualObject, isAutoBox)                                                                   \
     object_field(VirtualObject, type, "Ljdk/vm/ci/meta/ResolvedJavaType;")                                    \
     objectarray_field(VirtualObject, values, "[Ljdk/vm/ci/meta/JavaValue;")                                   \
     objectarray_field(VirtualObject, slotKinds, "[Ljdk/vm/ci/meta/JavaKind;")                                 \
--- a/src/hotspot/share/runtime/deoptimization.cpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/runtime/deoptimization.cpp	Mon Jun 03 13:21:02 2019 -0700
@@ -50,7 +50,10 @@
 #include "runtime/biasedLocking.hpp"
 #include "runtime/compilationPolicy.hpp"
 #include "runtime/deoptimization.hpp"
+#include "runtime/fieldDescriptor.hpp"
+#include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/frame.inline.hpp"
+#include "runtime/jniHandles.inline.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/safepointVerifiers.hpp"
@@ -232,7 +235,7 @@
       }
       if (objects != NULL) {
         JRT_BLOCK
-          realloc_failures = realloc_objects(thread, &deoptee, objects, THREAD);
+          realloc_failures = realloc_objects(thread, &deoptee, &map, objects, THREAD);
         JRT_END
         bool skip_internal = (cm != NULL) && !cm->is_compiled_by_jvmci();
         reassign_fields(&deoptee, &map, objects, realloc_failures, skip_internal);
@@ -810,8 +813,131 @@
 Deoptimization::DeoptAction Deoptimization::_unloaded_action
   = Deoptimization::Action_reinterpret;
 
+
+
+#if INCLUDE_JVMCI || INCLUDE_AOT
+template<typename CacheType>
+class BoxCacheBase : public CHeapObj<mtCompiler> {
+protected:
+  static InstanceKlass* find_cache_klass(Symbol* klass_name, TRAPS) {
+    ResourceMark rm;
+    char* klass_name_str = klass_name->as_C_string();
+    Klass* k = SystemDictionary::find(klass_name, Handle(), Handle(), THREAD);
+    guarantee(k != NULL, "%s must be loaded", klass_name_str);
+    InstanceKlass* ik = InstanceKlass::cast(k);
+    guarantee(ik->is_initialized(), "%s must be initialized", klass_name_str);
+    CacheType::compute_offsets(ik);
+    return ik;
+  }
+};
+
+template<typename PrimitiveType, typename CacheType, typename BoxType> class BoxCache  : public BoxCacheBase<CacheType> {
+  PrimitiveType _low;
+  PrimitiveType _high;
+  jobject _cache;
+protected:
+  static BoxCache<PrimitiveType, CacheType, BoxType> *_singleton;
+  BoxCache(Thread* thread) {
+    InstanceKlass* ik = BoxCacheBase<CacheType>::find_cache_klass(CacheType::symbol(), thread);
+    objArrayOop cache = CacheType::cache(ik);
+    assert(cache->length() > 0, "Empty cache");
+    _low = BoxType::value(cache->obj_at(0));
+    _high = _low + cache->length() - 1;
+    _cache = JNIHandles::make_global(Handle(thread, cache));
+  }
+  ~BoxCache() {
+    JNIHandles::destroy_global(_cache);
+  }
+public:
+  static BoxCache<PrimitiveType, CacheType, BoxType>* singleton(Thread* thread) {
+    if (_singleton == NULL) {
+      BoxCache<PrimitiveType, CacheType, BoxType>* s = new BoxCache<PrimitiveType, CacheType, BoxType>(thread);
+      if (!Atomic::replace_if_null(s, &_singleton)) {
+        delete s;
+      }
+    }
+    return _singleton;
+  }
+  oop lookup(PrimitiveType value) {
+    if (_low <= value && value <= _high) {
+      int offset = value - _low;
+      return objArrayOop(JNIHandles::resolve_non_null(_cache))->obj_at(offset);
+    }
+    return NULL;
+  }
+};
+
+typedef BoxCache<jint, java_lang_Integer_IntegerCache, java_lang_Integer> IntegerBoxCache;
+typedef BoxCache<jlong, java_lang_Long_LongCache, java_lang_Long> LongBoxCache;
+typedef BoxCache<jchar, java_lang_Character_CharacterCache, java_lang_Character> CharacterBoxCache;
+typedef BoxCache<jshort, java_lang_Short_ShortCache, java_lang_Short> ShortBoxCache;
+typedef BoxCache<jbyte, java_lang_Byte_ByteCache, java_lang_Byte> ByteBoxCache;
+
+template<> BoxCache<jint, java_lang_Integer_IntegerCache, java_lang_Integer>* BoxCache<jint, java_lang_Integer_IntegerCache, java_lang_Integer>::_singleton = NULL;
+template<> BoxCache<jlong, java_lang_Long_LongCache, java_lang_Long>* BoxCache<jlong, java_lang_Long_LongCache, java_lang_Long>::_singleton = NULL;
+template<> BoxCache<jchar, java_lang_Character_CharacterCache, java_lang_Character>* BoxCache<jchar, java_lang_Character_CharacterCache, java_lang_Character>::_singleton = NULL;
+template<> BoxCache<jshort, java_lang_Short_ShortCache, java_lang_Short>* BoxCache<jshort, java_lang_Short_ShortCache, java_lang_Short>::_singleton = NULL;
+template<> BoxCache<jbyte, java_lang_Byte_ByteCache, java_lang_Byte>* BoxCache<jbyte, java_lang_Byte_ByteCache, java_lang_Byte>::_singleton = NULL;
+
+class BooleanBoxCache : public BoxCacheBase<java_lang_Boolean> {
+  jobject _true_cache;
+  jobject _false_cache;
+protected:
+  static BooleanBoxCache *_singleton;
+  BooleanBoxCache(Thread *thread) {
+    InstanceKlass* ik = find_cache_klass(java_lang_Boolean::symbol(), thread);
+    _true_cache = JNIHandles::make_global(Handle(thread, java_lang_Boolean::get_TRUE(ik)));
+    _false_cache = JNIHandles::make_global(Handle(thread, java_lang_Boolean::get_FALSE(ik)));
+  }
+  ~BooleanBoxCache() {
+    JNIHandles::destroy_global(_true_cache);
+    JNIHandles::destroy_global(_false_cache);
+  }
+public:
+  static BooleanBoxCache* singleton(Thread* thread) {
+    if (_singleton == NULL) {
+      BooleanBoxCache* s = new BooleanBoxCache(thread);
+      if (!Atomic::replace_if_null(s, &_singleton)) {
+        delete s;
+      }
+    }
+    return _singleton;
+  }
+  oop lookup(jboolean value) {
+    if (value != 0) {
+      return JNIHandles::resolve_non_null(_true_cache);
+    }
+    return JNIHandles::resolve_non_null(_false_cache);
+  }
+};
+
+BooleanBoxCache* BooleanBoxCache::_singleton = NULL;
+
+oop Deoptimization::get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, TRAPS) {
+   Klass* k = java_lang_Class::as_Klass(bv->klass()->as_ConstantOopReadValue()->value()());
+   BasicType box_type = SystemDictionary::box_klass_type(k);
+   if (box_type != T_OBJECT) {
+     StackValue* value = StackValue::create_stack_value(fr, reg_map, bv->field_at(0));
+     switch(box_type) {
+       case T_INT:     return IntegerBoxCache::singleton(THREAD)->lookup(value->get_int());
+       case T_LONG: {
+                       StackValue* low = StackValue::create_stack_value(fr, reg_map, bv->field_at(1));
+                       jlong res = (jlong)low->get_int();
+                       return LongBoxCache::singleton(THREAD)->lookup(res);
+                     }
+       case T_CHAR:    return CharacterBoxCache::singleton(THREAD)->lookup(value->get_int());
+       case T_SHORT:   return ShortBoxCache::singleton(THREAD)->lookup(value->get_int());
+       case T_BYTE:    return ByteBoxCache::singleton(THREAD)->lookup(value->get_int());
+       case T_BOOLEAN: return BooleanBoxCache::singleton(THREAD)->lookup(value->get_int());
+       default:;
+     }
+   }
+   return NULL;
+}
+#endif // INCLUDE_JVMCI || INCLUDE_AOT
+
 #if COMPILER2_OR_JVMCI
-bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS) {
+bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, TRAPS) {
   Handle pending_exception(THREAD, thread->pending_exception());
   const char* exception_file = thread->exception_file();
   int exception_line = thread->exception_line();
@@ -827,8 +953,21 @@
     oop obj = NULL;
 
     if (k->is_instance_klass()) {
+#if INCLUDE_JVMCI || INCLUDE_AOT
+      CompiledMethod* cm = fr->cb()->as_compiled_method_or_null();
+      if (cm->is_compiled_by_jvmci() && sv->is_auto_box()) {
+        AutoBoxObjectValue* abv = (AutoBoxObjectValue*) sv;
+        obj = get_cached_box(abv, fr, reg_map, THREAD);
+        if (obj != NULL) {
+          // Set the flag to indicate the box came from a cache, so that we can skip the field reassignment for it.
+          abv->set_cached(true);
+        }
+      }
+#endif // INCLUDE_JVMCI || INCLUDE_AOT
       InstanceKlass* ik = InstanceKlass::cast(k);
-      obj = ik->allocate_instance(THREAD);
+      if (obj == NULL) {
+        obj = ik->allocate_instance(THREAD);
+      }
     } else if (k->is_typeArray_klass()) {
       TypeArrayKlass* ak = TypeArrayKlass::cast(k);
       assert(sv->field_size() % type2size[ak->element_type()] == 0, "non-integral array length");
@@ -1101,7 +1240,12 @@
     if (obj.is_null()) {
       continue;
     }
-
+#if INCLUDE_JVMCI || INCLUDE_AOT
+    // Don't reassign fields of boxes that came from a cache. Caches may be in CDS.
+    if (sv->is_auto_box() && ((AutoBoxObjectValue*) sv)->is_cached()) {
+      continue;
+    }
+#endif // INCLUDE_JVMCI || INCLUDE_AOT
     if (k->is_instance_klass()) {
       InstanceKlass* ik = InstanceKlass::cast(k);
       reassign_fields_by_klass(ik, fr, reg_map, sv, 0, obj(), skip_internal);
--- a/src/hotspot/share/runtime/deoptimization.hpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/runtime/deoptimization.hpp	Mon Jun 03 13:21:02 2019 -0700
@@ -33,6 +33,7 @@
 class MonitorInfo;
 class MonitorValue;
 class ObjectValue;
+class AutoBoxObjectValue;
 class ScopeValue;
 class compiledVFrame;
 
@@ -153,6 +154,7 @@
 
 #if INCLUDE_JVMCI
   static address deoptimize_for_missing_exception_handler(CompiledMethod* cm);
+  static oop get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, TRAPS);
 #endif
 
   private:
@@ -169,7 +171,7 @@
 JVMCI_ONLY(public:)
 
   // Support for restoring non-escaping objects
-  static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS);
+  static bool realloc_objects(JavaThread* thread, frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, TRAPS);
   static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type);
   static void reassign_object_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, objArrayOop obj);
   static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures, bool skip_internal);
--- a/src/hotspot/share/runtime/thread.cpp	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/hotspot/share/runtime/thread.cpp	Mon Jun 03 13:21:02 2019 -0700
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "jvm.h"
+#include "aot/aotLoader.hpp"
 #include "classfile/classLoader.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/moduleEntry.hpp"
@@ -3650,6 +3651,9 @@
   initialize_class(vmSymbols::java_lang_StackOverflowError(), CHECK);
   initialize_class(vmSymbols::java_lang_IllegalMonitorStateException(), CHECK);
   initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK);
+
+  // Eager box cache initialization only if AOT is on and any library is loaded.
+  AOTLoader::initialize_box_caches(CHECK);
 }
 
 void Threads::initialize_jsr292_core_classes(TRAPS) {
@@ -3912,6 +3916,7 @@
     Chunk::start_chunk_pool_cleaner_task();
   }
 
+
   // initialize compiler(s)
 #if defined(COMPILER1) || COMPILER2_OR_JVMCI
 #if INCLUDE_JVMCI
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java	Mon Jun 03 13:21:02 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2019, 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
@@ -43,6 +43,7 @@
     private JavaValue[] values;
     private JavaKind[] slotKinds;
     private final int id;
+    private boolean isAutoBox;
 
     /**
      * Creates a new {@link VirtualObject} for the given type, with the given fields. If
@@ -58,12 +59,33 @@
      * @return a new {@link VirtualObject} instance.
      */
     public static VirtualObject get(ResolvedJavaType type, int id) {
-        return new VirtualObject(type, id);
+        return new VirtualObject(type, id, false);
     }
 
-    private VirtualObject(ResolvedJavaType type, int id) {
+    /**
+     * Creates a new {@link VirtualObject} for the given type, with the given fields. If
+     * {@code type} is an instance class then {@code values} provides the values for the fields
+     * returned by {@link ResolvedJavaType#getInstanceFields(boolean) getInstanceFields(true)}. If
+     * {@code type} is an array then the length of the values array determines the reallocated array
+     * length.
+     *
+     * @param type the type of the object whose allocation was removed during compilation. This can
+     *            be either an instance of an array type.
+     * @param id a unique id that identifies the object within the debug information for one
+     *            position in the compiled code.
+     * @param isAutoBox a flag that tells the runtime that the object may be a boxed primitive and
+     *            that it possibly needs to be obtained for the box cache instead of creating
+     *            a new instance.
+     * @return a new {@link VirtualObject} instance.
+     */
+    public static VirtualObject get(ResolvedJavaType type, int id, boolean isAutoBox) {
+        return new VirtualObject(type, id, isAutoBox);
+    }
+
+    private VirtualObject(ResolvedJavaType type, int id, boolean isAutoBox) {
         this.type = type;
         this.id = id;
+        this.isAutoBox = isAutoBox;
     }
 
     private static StringBuilder appendValue(StringBuilder buf, JavaValue value, Set<VirtualObject> visited) {
@@ -144,6 +166,23 @@
     }
 
     /**
+     * Returns true if the object is a box. For boxes the deoptimization would check if the value of
+     * the box is in the cache range and try to return a cached object.
+     */
+    public boolean isAutoBox() {
+      return isAutoBox;
+    }
+
+    /**
+     * Sets the value of the box flag.
+     * @param isAutoBox a flag that tells the runtime that the object may be a boxed primitive and that
+     *            it possibly needs to be obtained for the box cache instead of creating a new instance.
+     */
+    public void setIsAutoBox(boolean isAutoBox) {
+      this.isAutoBox = isAutoBox;
+    }
+
+    /**
      * Overwrites the current set of values with a new one.
      *
      * @param values an array containing all the values to be stored into the object when it is
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Mon Jun 03 13:21:02 2019 -0700
@@ -187,6 +187,9 @@
                     // initialized.
                     JVMCI.getRuntime();
                 }
+                // Make sure all the primitive box caches are populated (required to properly materialize boxed primitives
+                // during deoptimization).
+                Object[] boxCaches = { Boolean.valueOf(false), Byte.valueOf((byte)0), Short.valueOf((short) 0), Character.valueOf((char) 0), Integer.valueOf(0), Long.valueOf(0) };
             }
         }
         return result;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java	Mon Jun 03 13:21:02 2019 -0700
@@ -43,7 +43,9 @@
 import org.graalvm.compiler.nodes.spi.NodeValueMap;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
+import org.graalvm.compiler.nodes.virtual.VirtualBoxingNode;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.serviceprovider.GraalServices;
 import org.graalvm.compiler.virtual.nodes.MaterializedObjectState;
 import org.graalvm.compiler.virtual.nodes.VirtualObjectState;
 
@@ -154,6 +156,10 @@
                 }
                 assert checkValues(vobjValue.getType(), values, slotKinds);
                 vobjValue.setValues(values, slotKinds);
+
+                if (vobjNode instanceof VirtualBoxingNode) {
+                    GraalServices.markVirtualObjectAsAutoBox(vobjValue);
+                }
             }
 
             virtualObjectsArray = new VirtualObject[virtualObjects.size()];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/BoxDeoptimizationTest.java	Mon Jun 03 13:21:02 2019 -0700
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class BoxDeoptimizationTest extends GraalCompilerTest {
+    private static boolean isJDK13OrLater = JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 13;
+
+    public static void testInteger() {
+        Object[] values = {42, new Exception()};
+        GraalDirectives.deoptimize();
+        Assert.assertSame(values[0], Integer.valueOf(42));
+    }
+
+    @Test
+    public void test1() {
+        Assume.assumeTrue(isJDK13OrLater);
+        test("testInteger");
+    }
+
+    public static void testLong() {
+        Object[] values = {42L, new Exception()};
+        GraalDirectives.deoptimize();
+        Assert.assertSame(values[0], Long.valueOf(42));
+    }
+
+    @Test
+    public void test2() {
+        Assume.assumeTrue(isJDK13OrLater);
+        test("testLong");
+    }
+
+    public static void testChar() {
+        Object[] values = {'a', new Exception()};
+        GraalDirectives.deoptimize();
+        Assert.assertSame(values[0], Character.valueOf('a'));
+    }
+
+    @Test
+    public void test3() {
+        Assume.assumeTrue(isJDK13OrLater);
+        test("testChar");
+    }
+
+    public static void testShort() {
+        Object[] values = {(short) 42, new Exception()};
+        GraalDirectives.deoptimize();
+        Assert.assertSame(values[0], Short.valueOf((short) 42));
+    }
+
+    @Test
+    public void test4() {
+        Assume.assumeTrue(isJDK13OrLater);
+        test("testShort");
+    }
+
+    public static void testByte() {
+        Object[] values = {(byte) 42, new Exception()};
+        GraalDirectives.deoptimize();
+        Assert.assertSame(values[0], Byte.valueOf((byte) 42));
+    }
+
+    @Test
+    public void test5() {
+        Assume.assumeTrue(isJDK13OrLater);
+        test("testByte");
+    }
+
+    public static void testBoolean() {
+        Object[] values = {true, new Exception()};
+        GraalDirectives.deoptimize();
+        Assert.assertSame(values[0], Boolean.valueOf(true));
+    }
+
+    @Test
+    public void test6() {
+        Assume.assumeTrue(isJDK13OrLater);
+        test("testBoolean");
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Mon Jun 03 21:28:45 2019 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Mon Jun 03 13:21:02 2019 -0700
@@ -42,6 +42,7 @@
 import org.graalvm.compiler.serviceprovider.SpeculationReasonGroup.SpeculationContextObject;
 
 import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.code.VirtualObject;
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -519,4 +520,12 @@
     public static double fma(double a, double b, double c) {
         return Math.fma(a, b, c);
     }
+
+    /**
+     * Set the flag in the {@link VirtualObject} that indicates that it is a boxed primitive that
+     * was produced as a result of a call to a {@code valueOf} method.
+     */
+    public static void markVirtualObjectAsAutoBox(VirtualObject virtualObject) {
+       virtualObject.setIsAutoBox(true);
+    }
 }