< prev index next >

src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java

Print this page
*** 130,13 ***
          if (member.isConstructor())
              return makeAllocator(member.getDeclaringClass(), member);
          return make(member.getDeclaringClass(), member);
      }
      static DirectMethodHandle makeAllocator(Class<?> instanceClass, MemberName ctor) {
!         assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
          ctor = ctor.asConstructor();
!         assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
          MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
          LambdaForm lform = preparedLambdaForm(ctor);
          MemberName init = ctor.asSpecial();
          assert(init.getMethodType().returnType() == void.class);
          return new Constructor(mtype, lform, ctor, true, init, instanceClass);
--- 130,13 ---
          if (member.isConstructor())
              return makeAllocator(member.getDeclaringClass(), member);
          return make(member.getDeclaringClass(), member);
      }
      static DirectMethodHandle makeAllocator(Class<?> instanceClass, MemberName ctor) {
!         assert(ctor.isConstructor()) : ctor;
          ctor = ctor.asConstructor();
!         assert(ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
          MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
          LambdaForm lform = preparedLambdaForm(ctor);
          MemberName init = ctor.asSpecial();
          assert(init.getMethodType().returnType() == void.class);
          return new Constructor(mtype, lform, ctor, true, init, instanceClass);

*** 602,10 ***
--- 602,25 ---
      /*non-public*/
      static Object checkCast(Object mh, Object obj) {
          return ((DirectMethodHandle) mh).checkCast(obj);
      }
  
+     @ForceInline
+     /*non-public*/ static Class<?> fieldType(Object accessorObj) {
+         return ((Accessor) accessorObj).fieldType;
+     }
+ 
+     @ForceInline
+     /*non-public*/ static Class<?> staticFieldType(Object accessorObj) {
+         return ((StaticAccessor) accessorObj).fieldType;
+     }
+ 
+     @ForceInline
+     /*non-public*/ static Object zeroInstanceIfNull(Class<?> fieldType, Object obj) {
+         return obj != null ? obj : UNSAFE.uninitializedDefaultValue(fieldType);
+     }
+ 
      Object checkCast(Object obj) {
          return member.getMethodType().returnType().cast(obj);
      }
  
      // Caching machinery for field accessors:

*** 616,77 ***
              AF_PUTSTATIC       = 3,
              AF_GETSTATIC_INIT  = 4,
              AF_PUTSTATIC_INIT  = 5,
              AF_LIMIT           = 6;
      // Enumerate the different field kinds using Wrapper,
!     // with an extra case added for checked references.
      static final int
!             FT_LAST_WRAPPER    = Wrapper.COUNT-1,
!             FT_UNCHECKED_REF   = Wrapper.OBJECT.ordinal(),
!             FT_CHECKED_REF     = FT_LAST_WRAPPER+1,
!             FT_LIMIT           = FT_LAST_WRAPPER+2;
!     private static int afIndex(byte formOp, boolean isVolatile, int ftypeKind) {
          return ((formOp * FT_LIMIT * 2)
                  + (isVolatile ? FT_LIMIT : 0)
                  + ftypeKind);
      }
      @Stable
      private static final LambdaForm[] ACCESSOR_FORMS
!             = new LambdaForm[afIndex(AF_LIMIT, false, 0)];
      static int ftypeKind(Class<?> ftype) {
          if (ftype.isPrimitive()) {
              return Wrapper.forPrimitiveType(ftype).ordinal();
          } else if (ftype.isInterface() || ftype.isAssignableFrom(Object.class)) {
              // retyping can be done without a cast
              return FT_UNCHECKED_REF;
          } else {
!             return FT_CHECKED_REF;
          }
      }
  
      /**
       * Create a LF which can access the given field.
       * Cache and share this structure among all fields with
       * the same basicType and refKind.
       */
      private static LambdaForm preparedFieldLambdaForm(MemberName m) {
          Class<?> ftype = m.getFieldType();
-         boolean isVolatile = m.isVolatile();
          byte formOp = switch (m.getReferenceKind()) {
              case REF_getField  -> AF_GETFIELD;
              case REF_putField  -> AF_PUTFIELD;
              case REF_getStatic -> AF_GETSTATIC;
              case REF_putStatic -> AF_PUTSTATIC;
              default -> throw new InternalError(m.toString());
          };
          if (shouldBeInitialized(m)) {
              // precompute the barrier-free version:
!             preparedFieldLambdaForm(formOp, isVolatile, ftype);
              assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
                     (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
              formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
          }
!         LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
          maybeCompile(lform, m);
          assert(lform.methodType().dropParameterTypes(0, 1)
                  .equals(m.getInvocationType().basicType()))
                  : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
          return lform;
      }
!     private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
          int ftypeKind = ftypeKind(ftype);
!         int afIndex = afIndex(formOp, isVolatile, ftypeKind);
          LambdaForm lform = ACCESSOR_FORMS[afIndex];
          if (lform != null)  return lform;
!         lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind);
          ACCESSOR_FORMS[afIndex] = lform;  // don't bother with a CAS
          return lform;
      }
  
      private static final Wrapper[] ALL_WRAPPERS = Wrapper.values();
  
!     private static Kind getFieldKind(boolean isGetter, boolean isVolatile, Wrapper wrapper) {
          if (isGetter) {
              if (isVolatile) {
                  switch (wrapper) {
                      case BOOLEAN: return GET_BOOLEAN_VOLATILE;
                      case BYTE:    return GET_BYTE_VOLATILE;
--- 631,81 ---
              AF_PUTSTATIC       = 3,
              AF_GETSTATIC_INIT  = 4,
              AF_PUTSTATIC_INIT  = 5,
              AF_LIMIT           = 6;
      // Enumerate the different field kinds using Wrapper,
!     // with an extra case added for checked references and value field access
      static final int
!             FT_LAST_WRAPPER     = Wrapper.COUNT-1,
!             FT_UNCHECKED_REF    = Wrapper.OBJECT.ordinal(),
!             FT_CHECKED_REF      = FT_LAST_WRAPPER+1,
!             FT_CHECKED_VALUE    = FT_LAST_WRAPPER+2,  // flat vs non-flat x null value vs null-restricted value
!             FT_LIMIT            = FT_LAST_WRAPPER+6;
+     private static int afIndex(byte formOp, boolean isVolatile, boolean isFlat, boolean isNullRestricted, int ftypeKind) {
          return ((formOp * FT_LIMIT * 2)
                  + (isVolatile ? FT_LIMIT : 0)
+                 + (isFlat ? 1 : 0)
+                 + (isNullRestricted ? 1 : 0)
                  + ftypeKind);
      }
      @Stable
      private static final LambdaForm[] ACCESSOR_FORMS
!             = new LambdaForm[afIndex(AF_LIMIT, false, false, false, 0)];
      static int ftypeKind(Class<?> ftype) {
          if (ftype.isPrimitive()) {
              return Wrapper.forPrimitiveType(ftype).ordinal();
          } else if (ftype.isInterface() || ftype.isAssignableFrom(Object.class)) {
              // retyping can be done without a cast
              return FT_UNCHECKED_REF;
          } else {
!             return ftype.isValue() ? FT_CHECKED_VALUE : FT_CHECKED_REF;
          }
      }
  
      /**
       * Create a LF which can access the given field.
       * Cache and share this structure among all fields with
       * the same basicType and refKind.
       */
      private static LambdaForm preparedFieldLambdaForm(MemberName m) {
          Class<?> ftype = m.getFieldType();
          byte formOp = switch (m.getReferenceKind()) {
              case REF_getField  -> AF_GETFIELD;
              case REF_putField  -> AF_PUTFIELD;
              case REF_getStatic -> AF_GETSTATIC;
              case REF_putStatic -> AF_PUTSTATIC;
              default -> throw new InternalError(m.toString());
          };
          if (shouldBeInitialized(m)) {
              // precompute the barrier-free version:
!             preparedFieldLambdaForm(formOp, m.isVolatile(), m.isFlat(), m.isNullRestricted(), ftype);
              assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
                     (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
              formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
          }
!         LambdaForm lform = preparedFieldLambdaForm(formOp, m.isVolatile(), m.isFlat(), m.isNullRestricted(), ftype);
          maybeCompile(lform, m);
          assert(lform.methodType().dropParameterTypes(0, 1)
                  .equals(m.getInvocationType().basicType()))
                  : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
          return lform;
      }
! 
+     private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile,
+                                                       boolean isFlat, boolean isNullRestricted, Class<?> ftype) {
          int ftypeKind = ftypeKind(ftype);
!         int afIndex = afIndex(formOp, isVolatile, isFlat, isNullRestricted, ftypeKind);
          LambdaForm lform = ACCESSOR_FORMS[afIndex];
          if (lform != null)  return lform;
!         lform = makePreparedFieldLambdaForm(formOp, isVolatile,isFlat, isNullRestricted, ftypeKind);
          ACCESSOR_FORMS[afIndex] = lform;  // don't bother with a CAS
          return lform;
      }
  
      private static final Wrapper[] ALL_WRAPPERS = Wrapper.values();
  
!     private static Kind getFieldKind(boolean isGetter, boolean isVolatile, boolean isFlat, Wrapper wrapper) {
          if (isGetter) {
              if (isVolatile) {
                  switch (wrapper) {
                      case BOOLEAN: return GET_BOOLEAN_VOLATILE;
                      case BYTE:    return GET_BYTE_VOLATILE;

*** 694,11 ***
                      case CHAR:    return GET_CHAR_VOLATILE;
                      case INT:     return GET_INT_VOLATILE;
                      case LONG:    return GET_LONG_VOLATILE;
                      case FLOAT:   return GET_FLOAT_VOLATILE;
                      case DOUBLE:  return GET_DOUBLE_VOLATILE;
!                     case OBJECT:  return GET_REFERENCE_VOLATILE;
                  }
              } else {
                  switch (wrapper) {
                      case BOOLEAN: return GET_BOOLEAN;
                      case BYTE:    return GET_BYTE;
--- 713,11 ---
                      case CHAR:    return GET_CHAR_VOLATILE;
                      case INT:     return GET_INT_VOLATILE;
                      case LONG:    return GET_LONG_VOLATILE;
                      case FLOAT:   return GET_FLOAT_VOLATILE;
                      case DOUBLE:  return GET_DOUBLE_VOLATILE;
!                     case OBJECT:  return isFlat ? GET_VALUE_VOLATILE : GET_REFERENCE_VOLATILE;
                  }
              } else {
                  switch (wrapper) {
                      case BOOLEAN: return GET_BOOLEAN;
                      case BYTE:    return GET_BYTE;

*** 706,11 ***
                      case CHAR:    return GET_CHAR;
                      case INT:     return GET_INT;
                      case LONG:    return GET_LONG;
                      case FLOAT:   return GET_FLOAT;
                      case DOUBLE:  return GET_DOUBLE;
!                     case OBJECT:  return GET_REFERENCE;
                  }
              }
          } else {
              if (isVolatile) {
                  switch (wrapper) {
--- 725,11 ---
                      case CHAR:    return GET_CHAR;
                      case INT:     return GET_INT;
                      case LONG:    return GET_LONG;
                      case FLOAT:   return GET_FLOAT;
                      case DOUBLE:  return GET_DOUBLE;
!                     case OBJECT:  return isFlat ? GET_VALUE : GET_REFERENCE;
                  }
              }
          } else {
              if (isVolatile) {
                  switch (wrapper) {

*** 720,11 ***
                      case CHAR:    return PUT_CHAR_VOLATILE;
                      case INT:     return PUT_INT_VOLATILE;
                      case LONG:    return PUT_LONG_VOLATILE;
                      case FLOAT:   return PUT_FLOAT_VOLATILE;
                      case DOUBLE:  return PUT_DOUBLE_VOLATILE;
!                     case OBJECT:  return PUT_REFERENCE_VOLATILE;
                  }
              } else {
                  switch (wrapper) {
                      case BOOLEAN: return PUT_BOOLEAN;
                      case BYTE:    return PUT_BYTE;
--- 739,11 ---
                      case CHAR:    return PUT_CHAR_VOLATILE;
                      case INT:     return PUT_INT_VOLATILE;
                      case LONG:    return PUT_LONG_VOLATILE;
                      case FLOAT:   return PUT_FLOAT_VOLATILE;
                      case DOUBLE:  return PUT_DOUBLE_VOLATILE;
!                     case OBJECT:  return isFlat ? PUT_VALUE_VOLATILE : PUT_REFERENCE_VOLATILE;
                  }
              } else {
                  switch (wrapper) {
                      case BOOLEAN: return PUT_BOOLEAN;
                      case BYTE:    return PUT_BYTE;

*** 732,34 ***
                      case CHAR:    return PUT_CHAR;
                      case INT:     return PUT_INT;
                      case LONG:    return PUT_LONG;
                      case FLOAT:   return PUT_FLOAT;
                      case DOUBLE:  return PUT_DOUBLE;
!                     case OBJECT:  return PUT_REFERENCE;
                  }
              }
          }
          throw new AssertionError("Invalid arguments");
      }
  
!     static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
          boolean isGetter  = (formOp & 1) == (AF_GETFIELD & 1);
          boolean isStatic  = (formOp >= AF_GETSTATIC);
          boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
!         boolean needsCast = (ftypeKind == FT_CHECKED_REF);
          Wrapper fw = (needsCast ? Wrapper.OBJECT : ALL_WRAPPERS[ftypeKind]);
          Class<?> ft = fw.primitiveType();
!         assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
  
          // getObject, putIntVolatile, etc.
!         Kind kind = getFieldKind(isGetter, isVolatile, fw);
  
          MethodType linkerType;
!         if (isGetter)
!             linkerType = MethodType.methodType(ft, Object.class, long.class);
!         else
!             linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
          MemberName linker = new MemberName(Unsafe.class, kind.methodName, linkerType, REF_invokeVirtual);
          try {
              linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, LM_TRUSTED,
                                                NoSuchMethodException.class);
          } catch (ReflectiveOperationException ex) {
--- 751,45 ---
                      case CHAR:    return PUT_CHAR;
                      case INT:     return PUT_INT;
                      case LONG:    return PUT_LONG;
                      case FLOAT:   return PUT_FLOAT;
                      case DOUBLE:  return PUT_DOUBLE;
!                     case OBJECT:  return isFlat ? PUT_VALUE : PUT_REFERENCE;
                  }
              }
          }
          throw new AssertionError("Invalid arguments");
      }
  
!     /** invoked by GenerateJLIClassesHelper */
+     static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftype) {
+         return makePreparedFieldLambdaForm(formOp, isVolatile, false, false, ftype);
+     }
+ 
+     private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile,
+                                                           boolean isFlat, boolean isNullRestricted, int ftypeKind) {
          boolean isGetter  = (formOp & 1) == (AF_GETFIELD & 1);
          boolean isStatic  = (formOp >= AF_GETSTATIC);
          boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
!         boolean needsCast = (ftypeKind == FT_CHECKED_REF || ftypeKind == FT_CHECKED_VALUE);
          Wrapper fw = (needsCast ? Wrapper.OBJECT : ALL_WRAPPERS[ftypeKind]);
          Class<?> ft = fw.primitiveType();
!         assert(needsCast ? true : ftypeKind(ft) == ftypeKind);
  
          // getObject, putIntVolatile, etc.
!         Kind kind = getFieldKind(isGetter, isVolatile, isFlat, fw);
  
          MethodType linkerType;
!         if (isGetter) {
!             linkerType = isFlat
!                             ? MethodType.methodType(ft, Object.class, long.class, Class.class)
!                             : MethodType.methodType(ft, Object.class, long.class);
+         } else {
+             linkerType = isFlat
+                             ? MethodType.methodType(void.class, Object.class, long.class, Class.class, ft)
+                             : MethodType.methodType(void.class, Object.class, long.class, ft);
+         }
          MemberName linker = new MemberName(Unsafe.class, kind.methodName, linkerType, REF_invokeVirtual);
          try {
              linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, LM_TRUSTED,
                                                NoSuchMethodException.class);
          } catch (ReflectiveOperationException ex) {

*** 786,36 ***
          final int F_HOLDER  = (isStatic ? nameCursor++ : -1);  // static base if any
          final int F_OFFSET  = nameCursor++;  // Either static offset or field offset.
          final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
          final int U_HOLDER  = nameCursor++;  // UNSAFE holder
          final int INIT_BAR  = (needsInit ? nameCursor++ : -1);
          final int PRE_CAST  = (needsCast && !isGetter ? nameCursor++ : -1);
          final int LINKER_CALL = nameCursor++;
          final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
!         final int RESULT    = nameCursor-1;  // either the call or the cast
          Name[] names = invokeArguments(nameCursor - ARG_LIMIT, mtype);
          if (needsInit)
              names[INIT_BAR] = new Name(getFunction(NF_ensureInitialized), names[DMH_THIS]);
!         if (needsCast && !isGetter)
!             names[PRE_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[SET_VALUE]);
          Object[] outArgs = new Object[1 + linkerType.parameterCount()];
!         assert(outArgs.length == (isGetter ? 3 : 4));
          outArgs[0] = names[U_HOLDER] = new Name(getFunction(NF_UNSAFE));
          if (isStatic) {
              outArgs[1] = names[F_HOLDER]  = new Name(getFunction(NF_staticBase), names[DMH_THIS]);
              outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_staticOffset), names[DMH_THIS]);
          } else {
              outArgs[1] = names[OBJ_CHECK] = new Name(getFunction(NF_checkBase), names[OBJ_BASE]);
              outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_fieldOffset), names[DMH_THIS]);
          }
          if (!isGetter) {
!             outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
          }
          for (Object a : outArgs)  assert(a != null);
          names[LINKER_CALL] = new Name(linker, outArgs);
!         if (needsCast && isGetter)
!             names[POST_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[LINKER_CALL]);
          for (Name n : names)  assert(n != null);
  
          LambdaForm form;
          if (needsCast || needsInit) {
              // can't use the pre-generated form when casting and/or initializing
--- 816,58 ---
          final int F_HOLDER  = (isStatic ? nameCursor++ : -1);  // static base if any
          final int F_OFFSET  = nameCursor++;  // Either static offset or field offset.
          final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
          final int U_HOLDER  = nameCursor++;  // UNSAFE holder
          final int INIT_BAR  = (needsInit ? nameCursor++ : -1);
+         final int VALUE_TYPE = (isFlat ? nameCursor++ : -1);
+         final int NULL_CHECK  = (isNullRestricted && !isGetter ? nameCursor++ : -1);
          final int PRE_CAST  = (needsCast && !isGetter ? nameCursor++ : -1);
          final int LINKER_CALL = nameCursor++;
+         final int FIELD_TYPE = (isNullRestricted && isGetter ? nameCursor++ : -1);
+         final int ZERO_INSTANCE = (isNullRestricted && isGetter ? nameCursor++ : -1);
          final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
!         final int RESULT    = nameCursor-1;  // either the call, zero instance, or the cast
          Name[] names = invokeArguments(nameCursor - ARG_LIMIT, mtype);
          if (needsInit)
              names[INIT_BAR] = new Name(getFunction(NF_ensureInitialized), names[DMH_THIS]);
!         if (!isGetter) {
!             if (isNullRestricted)
+                 names[NULL_CHECK] = new Name(getFunction(NF_nullCheck), names[SET_VALUE]);
+             if (needsCast)
+                 names[PRE_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[SET_VALUE]);
+         }
          Object[] outArgs = new Object[1 + linkerType.parameterCount()];
!         assert (outArgs.length == (isGetter ? 3 : 4) + (isFlat ? 1 : 0));
          outArgs[0] = names[U_HOLDER] = new Name(getFunction(NF_UNSAFE));
          if (isStatic) {
              outArgs[1] = names[F_HOLDER]  = new Name(getFunction(NF_staticBase), names[DMH_THIS]);
              outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_staticOffset), names[DMH_THIS]);
          } else {
              outArgs[1] = names[OBJ_CHECK] = new Name(getFunction(NF_checkBase), names[OBJ_BASE]);
              outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_fieldOffset), names[DMH_THIS]);
          }
+         int x = 3;
+         if (isFlat) {
+             outArgs[x++] = names[VALUE_TYPE] = isStatic ? new Name(getFunction(NF_staticFieldType), names[DMH_THIS])
+                                                         : new Name(getFunction(NF_fieldType), names[DMH_THIS]);
+         }
          if (!isGetter) {
!             outArgs[x] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
          }
          for (Object a : outArgs)  assert(a != null);
          names[LINKER_CALL] = new Name(linker, outArgs);
!         if (isGetter) {
!             int argIndex = LINKER_CALL;
+             if (isNullRestricted) {
+                 names[FIELD_TYPE] = isStatic ? new Name(getFunction(NF_staticFieldType), names[DMH_THIS])
+                                              : new Name(getFunction(NF_fieldType), names[DMH_THIS]);
+                 names[ZERO_INSTANCE] = new Name(getFunction(NF_zeroInstance), names[FIELD_TYPE], names[LINKER_CALL]);
+                 argIndex = ZERO_INSTANCE;
+             }
+             if (needsCast)
+                 names[POST_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[argIndex]);
+         }
          for (Name n : names)  assert(n != null);
  
          LambdaForm form;
          if (needsCast || needsInit) {
              // can't use the pre-generated form when casting and/or initializing

*** 857,11 ***
              NF_checkCast = 7,
              NF_allocateInstance = 8,
              NF_constructorMethod = 9,
              NF_UNSAFE = 10,
              NF_checkReceiver = 11,
!             NF_LIMIT = 12;
  
      private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
  
      private static NamedFunction getFunction(byte func) {
          NamedFunction nf = NFS[func];
--- 909,15 ---
              NF_checkCast = 7,
              NF_allocateInstance = 8,
              NF_constructorMethod = 9,
              NF_UNSAFE = 10,
              NF_checkReceiver = 11,
!             NF_fieldType = 12,
+             NF_staticFieldType = 13,
+             NF_zeroInstance = 14,
+             NF_nullCheck = 15,
+             NF_LIMIT = 16;
  
      private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
  
      private static NamedFunction getFunction(byte func) {
          NamedFunction nf = NFS[func];

*** 872,10 ***
--- 928,12 ---
          nf = NFS[func] = createFunction(func);
          assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf));
          return nf;
      }
  
+     private static final MethodType CLS_OBJ_TYPE = MethodType.methodType(Class.class, Object.class);
+ 
      private static final MethodType OBJ_OBJ_TYPE = MethodType.methodType(Object.class, Object.class);
  
      private static final MethodType LONG_OBJ_TYPE = MethodType.methodType(long.class, Object.class);
  
      private static NamedFunction createFunction(byte func) {

*** 911,10 ***
--- 969,18 ---
                      member = new MemberName(DirectMethodHandle.class, "checkReceiver", OBJ_OBJ_TYPE, REF_invokeVirtual);
                      return new NamedFunction(
                              MemberName.getFactory().resolveOrFail(REF_invokeVirtual, member,
                                                                    DirectMethodHandle.class, LM_TRUSTED,
                                                                    NoSuchMethodException.class));
+                 case NF_fieldType:
+                     return getNamedFunction("fieldType", CLS_OBJ_TYPE);
+                 case NF_staticFieldType:
+                     return getNamedFunction("staticFieldType", CLS_OBJ_TYPE);
+                 case NF_zeroInstance:
+                     return getNamedFunction("zeroInstanceIfNull", MethodType.methodType(Object.class, Class.class, Object.class));
+                 case NF_nullCheck:
+                     return getNamedFunction("nullCheck", OBJ_OBJ_TYPE);
                  default:
                      throw newInternalError("Unknown function: " + func);
              }
          } catch (ReflectiveOperationException ex) {
              throw newInternalError(ex);
< prev index next >