diff src/share/vm/prims/jvmtiEnv.cpp @ 6725:da91efe96a93

6964458: Reimplement class meta-data storage to use native memory Summary: Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland Contributed-by: jmasa <jon.masamitsu@oracle.com>, stefank <stefan.karlsson@oracle.com>, mgerdin <mikael.gerdin@oracle.com>, never <tom.rodriguez@oracle.com>
author coleenp
date Sat, 01 Sep 2012 13:25:18 -0400
parents 04ade88d9712
children 18fb7da42534
line wrap: on
line diff
--- a/src/share/vm/prims/jvmtiEnv.cpp	Fri Aug 31 16:39:35 2012 -0700
+++ b/src/share/vm/prims/jvmtiEnv.cpp	Sat Sep 01 13:25:18 2012 -0400
@@ -30,7 +30,6 @@
 #include "jvmtifiles/jvmtiEnv.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.inline.hpp"
-#include "oops/cpCacheOop.hpp"
 #include "oops/instanceKlass.hpp"
 #include "prims/jniCheck.hpp"
 #include "prims/jvm_misc.hpp"
@@ -254,7 +253,7 @@
       return JVMTI_ERROR_UNMODIFIABLE_CLASS;
     }
 
-    klassOop k_oop = java_lang_Class::as_klassOop(k_mirror);
+    Klass* k_oop = java_lang_Class::as_Klass(k_mirror);
     KlassHandle klass(current_thread, k_oop);
 
     jint status = klass->jvmti_class_status();
@@ -269,10 +268,10 @@
     if (ikh->get_cached_class_file_bytes() == NULL) {
       // Not cached, we need to reconstitute the class file from the
       // VM representation. We don't attach the reconstituted class
-      // bytes to the instanceKlass here because they have not been
+      // bytes to the InstanceKlass here because they have not been
       // validated and we're not at a safepoint.
       constantPoolHandle  constants(current_thread, ikh->constants());
-      ObjectLocker ol(constants, current_thread);    // lock constant pool while we query it
+      MonitorLockerEx ml(constants->lock());    // lock constant pool while we query it
 
       JvmtiClassFileReconstituter reconstituter(ikh);
       if (reconstituter.get_error() != JVMTI_ERROR_NONE) {
@@ -316,14 +315,14 @@
   oop mirror = JNIHandles::resolve_external_guard(object);
   NULL_CHECK(mirror, JVMTI_ERROR_INVALID_OBJECT);
 
-  if (mirror->klass() == SystemDictionary::Class_klass()) {
-    if (!java_lang_Class::is_primitive(mirror)) {
-        mirror = java_lang_Class::as_klassOop(mirror);
-        assert(mirror != NULL, "class for non-primitive mirror must exist");
+  if (mirror->klass() == SystemDictionary::Class_klass() &&
+      !java_lang_Class::is_primitive(mirror)) {
+    Klass* k = java_lang_Class::as_Klass(mirror);
+    assert(k != NULL, "class for non-primitive mirror must exist");
+    *size_ptr = k->size() * wordSize;
+  } else {
+    *size_ptr = mirror->size() * wordSize;
     }
-  }
-
-  *size_ptr = mirror->size() * wordSize;
   return JVMTI_ERROR_NONE;
 } /* end GetObjectSize */
 
@@ -552,7 +551,7 @@
                               path,
                               THREAD);
       if (HAS_PENDING_EXCEPTION) {
-        Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
+        Symbol* ex_name = PENDING_EXCEPTION->klass()->name();
         CLEAR_PENDING_EXCEPTION;
 
         if (ex_name == vmSymbols::java_lang_NoSuchMethodError()) {
@@ -1620,7 +1619,7 @@
 jvmtiError
 JvmtiEnv::FollowReferences(jint heap_filter, jclass klass, jobject initial_object, const jvmtiHeapCallbacks* callbacks, const void* user_data) {
   // check klass if provided
-  klassOop k_oop = NULL;
+  Klass* k_oop = NULL;
   if (klass != NULL) {
     oop k_mirror = JNIHandles::resolve_external_guard(klass);
     if (k_mirror == NULL) {
@@ -1629,7 +1628,7 @@
     if (java_lang_Class::is_primitive(k_mirror)) {
       return JVMTI_ERROR_NONE;
     }
-    k_oop = java_lang_Class::as_klassOop(k_mirror);
+    k_oop = java_lang_Class::as_Klass(k_mirror);
     if (k_oop == NULL) {
       return JVMTI_ERROR_INVALID_CLASS;
     }
@@ -1651,7 +1650,7 @@
 jvmtiError
 JvmtiEnv::IterateThroughHeap(jint heap_filter, jclass klass, const jvmtiHeapCallbacks* callbacks, const void* user_data) {
   // check klass if provided
-  klassOop k_oop = NULL;
+  Klass* k_oop = NULL;
   if (klass != NULL) {
     oop k_mirror = JNIHandles::resolve_external_guard(klass);
     if (k_mirror == NULL) {
@@ -1660,7 +1659,7 @@
     if (java_lang_Class::is_primitive(k_mirror)) {
       return JVMTI_ERROR_NONE;
     }
-    k_oop = java_lang_Class::as_klassOop(k_mirror);
+    k_oop = java_lang_Class::as_Klass(k_mirror);
     if (k_oop == NULL) {
       return JVMTI_ERROR_INVALID_CLASS;
     }
@@ -1762,7 +1761,7 @@
     // DO PRIMITIVE CLASS PROCESSING
     return JVMTI_ERROR_NONE;
   }
-  klassOop k_oop = java_lang_Class::as_klassOop(k_mirror);
+  Klass* k_oop = java_lang_Class::as_Klass(k_mirror);
   if (k_oop == NULL) {
     return JVMTI_ERROR_INVALID_CLASS;
   }
@@ -1989,7 +1988,7 @@
 
 // method_oop - pre-checked for validity, but may be NULL meaning obsolete method
 jvmtiError
-JvmtiEnv::SetBreakpoint(methodOop method_oop, jlocation location) {
+JvmtiEnv::SetBreakpoint(Method* method_oop, jlocation location) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   if (location < 0) {   // simple invalid location check first
     return JVMTI_ERROR_INVALID_LOCATION;
@@ -2015,7 +2014,7 @@
 
 // method_oop - pre-checked for validity, but may be NULL meaning obsolete method
 jvmtiError
-JvmtiEnv::ClearBreakpoint(methodOop method_oop, jlocation location) {
+JvmtiEnv::ClearBreakpoint(Method* method_oop, jlocation location) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
 
   if (location < 0) {   // simple invalid location check first
@@ -2104,9 +2103,9 @@
 JvmtiEnv::GetClassSignature(oop k_mirror, char** signature_ptr, char** generic_ptr) {
   ResourceMark rm;
   bool isPrimitive = java_lang_Class::is_primitive(k_mirror);
-  klassOop k = NULL;
+  Klass* k = NULL;
   if (!isPrimitive) {
-    k = java_lang_Class::as_klassOop(k_mirror);
+    k = java_lang_Class::as_Klass(k_mirror);
     NULL_CHECK(k, JVMTI_ERROR_INVALID_CLASS);
   }
   if (signature_ptr != NULL) {
@@ -2126,7 +2125,7 @@
   if (generic_ptr != NULL) {
     *generic_ptr = NULL;
     if (!isPrimitive && Klass::cast(k)->oop_is_instance()) {
-      Symbol* soo = instanceKlass::cast(k)->generic_signature();
+      Symbol* soo = InstanceKlass::cast(k)->generic_signature();
       if (soo != NULL) {
         const char *gen_sig = soo->as_C_string();
         if (gen_sig != NULL) {
@@ -2154,7 +2153,7 @@
   if (java_lang_Class::is_primitive(k_mirror)) {
     result |= JVMTI_CLASS_STATUS_PRIMITIVE;
   } else {
-    klassOop k = java_lang_Class::as_klassOop(k_mirror);
+    Klass* k = java_lang_Class::as_Klass(k_mirror);
     NULL_CHECK(k, JVMTI_ERROR_INVALID_CLASS);
     result = Klass::cast(k)->jvmti_class_status();
   }
@@ -2171,14 +2170,14 @@
   if (java_lang_Class::is_primitive(k_mirror)) {
      return JVMTI_ERROR_ABSENT_INFORMATION;
   }
-  klassOop k_klass = java_lang_Class::as_klassOop(k_mirror);
+  Klass* k_klass = java_lang_Class::as_Klass(k_mirror);
   NULL_CHECK(k_klass, JVMTI_ERROR_INVALID_CLASS);
 
   if (!Klass::cast(k_klass)->oop_is_instance()) {
     return JVMTI_ERROR_ABSENT_INFORMATION;
   }
 
-  Symbol* sfnOop = instanceKlass::cast(k_klass)->source_file_name();
+  Symbol* sfnOop = InstanceKlass::cast(k_klass)->source_file_name();
   NULL_CHECK(sfnOop, JVMTI_ERROR_ABSENT_INFORMATION);
   {
     JavaThread* current_thread  = JavaThread::current();
@@ -2199,9 +2198,8 @@
   JavaThread* current_thread  = JavaThread::current();
   jint result = 0;
   if (!java_lang_Class::is_primitive(k_mirror)) {
-    klassOop k = java_lang_Class::as_klassOop(k_mirror);
+    Klass* k = java_lang_Class::as_Klass(k_mirror);
     NULL_CHECK(k, JVMTI_ERROR_INVALID_CLASS);
-    assert((Klass::cast(k)->oop_is_instance() || Klass::cast(k)->oop_is_array()), "should be an instance or an array klass");
     result = Klass::cast(k)->compute_modifier_flags(current_thread);
     JavaThread* THREAD = current_thread; // pass to macros
     if (HAS_PENDING_EXCEPTION) {
@@ -2235,7 +2233,7 @@
     *methods_ptr = (jmethodID*) jvmtiMalloc(0 * sizeof(jmethodID));
     return JVMTI_ERROR_NONE;
   }
-  klassOop k = java_lang_Class::as_klassOop(k_mirror);
+  Klass* k = java_lang_Class::as_Klass(k_mirror);
   NULL_CHECK(k, JVMTI_ERROR_INVALID_CLASS);
 
   // Return CLASS_NOT_PREPARED error as per JVMTI spec.
@@ -2257,8 +2255,8 @@
     // Use the original method ordering indices stored in the class, so we can emit
     // jmethodIDs in the order they appeared in the class file
     for (index = 0; index < result_length; index++) {
-      methodOop m = methodOop(instanceK_h->methods()->obj_at(index));
-      int original_index = instanceK_h->method_ordering()->int_at(index);
+      Method* m = instanceK_h->methods()->at(index);
+      int original_index = instanceK_h->method_ordering()->at(index);
       assert(original_index >= 0 && original_index < result_length, "invalid original method index");
       jmethodID id = m->jmethod_id();
       result_list[original_index] = id;
@@ -2266,7 +2264,7 @@
   } else {
     // otherwise just copy in any order
     for (index = 0; index < result_length; index++) {
-      methodOop m = methodOop(instanceK_h->methods()->obj_at(index));
+      Method* m = instanceK_h->methods()->at(index);
       jmethodID id = m->jmethod_id();
       result_list[index] = id;
     }
@@ -2291,7 +2289,7 @@
   }
   JavaThread* current_thread = JavaThread::current();
   HandleMark hm(current_thread);
-  klassOop k = java_lang_Class::as_klassOop(k_mirror);
+  Klass* k = java_lang_Class::as_Klass(k_mirror);
   NULL_CHECK(k, JVMTI_ERROR_INVALID_CLASS);
 
   // Return CLASS_NOT_PREPARED error as per JVMTI spec.
@@ -2346,7 +2344,7 @@
     }
     JavaThread* current_thread = JavaThread::current();
     HandleMark hm(current_thread);
-    klassOop k = java_lang_Class::as_klassOop(k_mirror);
+    Klass* k = java_lang_Class::as_Klass(k_mirror);
     NULL_CHECK(k, JVMTI_ERROR_INVALID_CLASS);
 
     // Return CLASS_NOT_PREPARED error as per JVMTI spec.
@@ -2359,15 +2357,14 @@
       return JVMTI_ERROR_NONE;
     }
 
-    objArrayHandle interface_list(current_thread, instanceKlass::cast(k)->local_interfaces());
-    const int result_length = (interface_list.is_null() ? 0 : interface_list->length());
+    Array<Klass*>* interface_list = InstanceKlass::cast(k)->local_interfaces();
+    const int result_length = (interface_list == NULL ? 0 : interface_list->length());
     jclass* result_list = (jclass*) jvmtiMalloc(result_length * sizeof(jclass));
     for (int i_index = 0; i_index < result_length; i_index += 1) {
-      oop oop_at = interface_list->obj_at(i_index);
-      assert(oop_at->is_klass(), "interfaces must be klassOops");
-      klassOop klassOop_at = klassOop(oop_at);      // ???: is there a better way?
-      assert(Klass::cast(klassOop_at)->is_interface(), "interfaces must be interfaces");
-      oop mirror_at = Klass::cast(klassOop_at)->java_mirror();
+      Klass* klass_at = interface_list->at(i_index);
+      assert(klass_at->is_klass(), "interfaces must be Klass*s");
+      assert(Klass::cast(klass_at)->is_interface(), "interfaces must be interfaces");
+      oop mirror_at = Klass::cast(klass_at)->java_mirror();
       Handle handle_at = Handle(current_thread, mirror_at);
       result_list[i_index] = (jclass) jni_reference(handle_at);
     }
@@ -2387,7 +2384,7 @@
   if (java_lang_Class::is_primitive(k_mirror)) {
     return JVMTI_ERROR_ABSENT_INFORMATION;
   }
-  klassOop k_oop = java_lang_Class::as_klassOop(k_mirror);
+  Klass* k_oop = java_lang_Class::as_Klass(k_mirror);
   Thread *thread = Thread::current();
   HandleMark hm(thread);
   KlassHandle klass(thread, k_oop);
@@ -2418,7 +2415,7 @@
     return JVMTI_ERROR_ABSENT_INFORMATION;
   }
 
-  klassOop k_oop = java_lang_Class::as_klassOop(k_mirror);
+  Klass* k_oop = java_lang_Class::as_Klass(k_mirror);
   Thread *thread = Thread::current();
   HandleMark hm(thread);
   ResourceMark rm(thread);
@@ -2434,7 +2431,7 @@
 
   instanceKlassHandle ikh(thread, k_oop);
   constantPoolHandle  constants(thread, ikh->constants());
-  ObjectLocker ol(constants, thread);    // lock constant pool while we query it
+  MonitorLockerEx ml(constants->lock());    // lock constant pool while we query it
 
   JvmtiConstantPoolReconstituter reconstituter(ikh);
   if (reconstituter.get_error() != JVMTI_ERROR_NONE) {
@@ -2470,7 +2467,7 @@
   {
     bool result = false;
     if (!java_lang_Class::is_primitive(k_mirror)) {
-      klassOop k = java_lang_Class::as_klassOop(k_mirror);
+      Klass* k = java_lang_Class::as_Klass(k_mirror);
       if (k != NULL && Klass::cast(k)->is_interface()) {
         result = true;
       }
@@ -2489,7 +2486,7 @@
   {
     bool result = false;
     if (!java_lang_Class::is_primitive(k_mirror)) {
-      klassOop k = java_lang_Class::as_klassOop(k_mirror);
+      Klass* k = java_lang_Class::as_Klass(k_mirror);
       if (k != NULL && Klass::cast(k)->oop_is_array()) {
         result = true;
       }
@@ -2512,7 +2509,7 @@
     }
     JavaThread* current_thread = JavaThread::current();
     HandleMark hm(current_thread);
-    klassOop k = java_lang_Class::as_klassOop(k_mirror);
+    Klass* k = java_lang_Class::as_Klass(k_mirror);
     NULL_CHECK(k, JVMTI_ERROR_INVALID_CLASS);
 
     oop result_oop = Klass::cast(k)->class_loader();
@@ -2536,12 +2533,12 @@
     if (java_lang_Class::is_primitive(k_mirror)) {
       return JVMTI_ERROR_ABSENT_INFORMATION;
     }
-    klassOop k = java_lang_Class::as_klassOop(k_mirror);
+    Klass* k = java_lang_Class::as_Klass(k_mirror);
     NULL_CHECK(k, JVMTI_ERROR_INVALID_CLASS);
     if (!Klass::cast(k)->oop_is_instance()) {
       return JVMTI_ERROR_ABSENT_INFORMATION;
     }
-    char* sde = instanceKlass::cast(k)->source_debug_extension();
+    char* sde = InstanceKlass::cast(k)->source_debug_extension();
     NULL_CHECK(sde, JVMTI_ERROR_ABSENT_INFORMATION);
 
     {
@@ -2672,7 +2669,7 @@
 // signature_ptr - NULL is a valid value, must be checked
 // generic_ptr - NULL is a valid value, must be checked
 jvmtiError
-JvmtiEnv::GetMethodName(methodOop method_oop, char** name_ptr, char** signature_ptr, char** generic_ptr) {
+JvmtiEnv::GetMethodName(Method* method_oop, char** name_ptr, char** signature_ptr, char** generic_ptr) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   JavaThread* current_thread  = JavaThread::current();
 
@@ -2713,7 +2710,7 @@
 // method_oop - pre-checked for validity, but may be NULL meaning obsolete method
 // declaring_class_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::GetMethodDeclaringClass(methodOop method_oop, jclass* declaring_class_ptr) {
+JvmtiEnv::GetMethodDeclaringClass(Method* method_oop, jclass* declaring_class_ptr) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   (*declaring_class_ptr) = get_jni_class_non_null(method_oop->method_holder());
   return JVMTI_ERROR_NONE;
@@ -2723,7 +2720,7 @@
 // method_oop - pre-checked for validity, but may be NULL meaning obsolete method
 // modifiers_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::GetMethodModifiers(methodOop method_oop, jint* modifiers_ptr) {
+JvmtiEnv::GetMethodModifiers(Method* method_oop, jint* modifiers_ptr) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   (*modifiers_ptr) = method_oop->access_flags().as_int() & JVM_RECOGNIZED_METHOD_MODIFIERS;
   return JVMTI_ERROR_NONE;
@@ -2733,7 +2730,7 @@
 // method_oop - pre-checked for validity, but may be NULL meaning obsolete method
 // max_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::GetMaxLocals(methodOop method_oop, jint* max_ptr) {
+JvmtiEnv::GetMaxLocals(Method* method_oop, jint* max_ptr) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   // get max stack
   (*max_ptr) = method_oop->max_locals();
@@ -2744,7 +2741,7 @@
 // method_oop - pre-checked for validity, but may be NULL meaning obsolete method
 // size_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::GetArgumentsSize(methodOop method_oop, jint* size_ptr) {
+JvmtiEnv::GetArgumentsSize(Method* method_oop, jint* size_ptr) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   // get size of arguments
 
@@ -2757,7 +2754,7 @@
 // entry_count_ptr - pre-checked for NULL
 // table_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::GetLineNumberTable(methodOop method_oop, jint* entry_count_ptr, jvmtiLineNumberEntry** table_ptr) {
+JvmtiEnv::GetLineNumberTable(Method* method_oop, jint* entry_count_ptr, jvmtiLineNumberEntry** table_ptr) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   if (!method_oop->has_linenumber_table()) {
     return (JVMTI_ERROR_ABSENT_INFORMATION);
@@ -2799,7 +2796,7 @@
 // start_location_ptr - pre-checked for NULL
 // end_location_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::GetMethodLocation(methodOop method_oop, jlocation* start_location_ptr, jlocation* end_location_ptr) {
+JvmtiEnv::GetMethodLocation(Method* method_oop, jlocation* start_location_ptr, jlocation* end_location_ptr) {
 
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   // get start and end location
@@ -2819,18 +2816,18 @@
 // entry_count_ptr - pre-checked for NULL
 // table_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::GetLocalVariableTable(methodOop method_oop, jint* entry_count_ptr, jvmtiLocalVariableEntry** table_ptr) {
+JvmtiEnv::GetLocalVariableTable(Method* method_oop, jint* entry_count_ptr, jvmtiLocalVariableEntry** table_ptr) {
 
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   JavaThread* current_thread  = JavaThread::current();
 
   // does the klass have any local variable information?
-  instanceKlass* ik = instanceKlass::cast(method_oop->method_holder());
+  InstanceKlass* ik = InstanceKlass::cast(method_oop->method_holder());
   if (!ik->access_flags().has_localvariable_table()) {
     return (JVMTI_ERROR_ABSENT_INFORMATION);
   }
 
-  constantPoolOop constants = method_oop->constants();
+  ConstantPool* constants = method_oop->constants();
   NULL_CHECK(constants, JVMTI_ERROR_ABSENT_INFORMATION);
 
   // in the vm localvariable table representation, 6 consecutive elements in the table
@@ -2896,7 +2893,7 @@
 // bytecode_count_ptr - pre-checked for NULL
 // bytecodes_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::GetBytecodes(methodOop method_oop, jint* bytecode_count_ptr, unsigned char** bytecodes_ptr) {
+JvmtiEnv::GetBytecodes(Method* method_oop, jint* bytecode_count_ptr, unsigned char** bytecodes_ptr) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
 
   HandleMark hm;
@@ -2918,7 +2915,7 @@
 // method_oop - pre-checked for validity, but may be NULL meaning obsolete method
 // is_native_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::IsMethodNative(methodOop method_oop, jboolean* is_native_ptr) {
+JvmtiEnv::IsMethodNative(Method* method_oop, jboolean* is_native_ptr) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   (*is_native_ptr) = method_oop->is_native();
   return JVMTI_ERROR_NONE;
@@ -2928,7 +2925,7 @@
 // method_oop - pre-checked for validity, but may be NULL meaning obsolete method
 // is_synthetic_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::IsMethodSynthetic(methodOop method_oop, jboolean* is_synthetic_ptr) {
+JvmtiEnv::IsMethodSynthetic(Method* method_oop, jboolean* is_synthetic_ptr) {
   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
   (*is_synthetic_ptr) = method_oop->is_synthetic();
   return JVMTI_ERROR_NONE;
@@ -2938,7 +2935,7 @@
 // method_oop - pre-checked for validity, but may be NULL meaning obsolete method
 // is_obsolete_ptr - pre-checked for NULL
 jvmtiError
-JvmtiEnv::IsMethodObsolete(methodOop method_oop, jboolean* is_obsolete_ptr) {
+JvmtiEnv::IsMethodObsolete(Method* method_oop, jboolean* is_obsolete_ptr) {
   if (use_version_1_0_semantics() &&
       get_capabilities()->can_redefine_classes == 0) {
     // This JvmtiEnv requested version 1.0 semantics and this function