5.4.3 Resolution

Many Java Virtual Machine instructions - anewarray, checkcast, getfield, getstatic, instanceof, invokedynamic, invokeinterface, invokespecial, invokestatic, invokevirtual, ldc, ldc_w, ldc2_w, multianewarray, new, putfield, and putstatic - rely on symbolic references in the run-time constant pool. Execution of any of these instructions requires resolution of the symbolic reference. Resolution is the process of dynamically determining one or more concrete values from a symbolic reference in the run-time constant pool. Initially, all symbolic references in the run-time constant pool are unresolved. Resolution of an unresolved symbolic reference to (i) a class or interface, (ii) a field, (iii) a method, (iv) a method type, (v) a method handle, or (vi) a dynamically-computed constant, proceeds in accordance with the rules given in §5.4.3.1 through §5.4.3.5. In the first three of those sections, the class or interface in whose run-time constant pool the symbolic reference appears is labeled D. Then:

  • If no error occurs during resolution of the symbolic reference, then resolution succeeds. Subsequent attempts to resolve the symbolic reference always succeed trivially and result in the same entity produced by the initial resolution. If the symbolic reference is to a dynamically-computed constant, the bootstrap method is not re-executed for these subsequent attempts.

  • If an error occurs during resolution of the symbolic reference, then it is either (i) an instance of IncompatibleClassChangeError (or a subclass); (ii) an instance of Error (or a subclass) that arose from resolution or invocation of a bootstrap method; or (iii) an instance of LinkageError (or a subclass) that arose because class loading failed or a loader constraint was violated. The error must be thrown at a point in the program that (directly or indirectly) uses the symbolic reference. Subsequent attempts to resolve the symbolic reference always fail with the same error that was thrown as a result of the initial resolution attempt. If the symbolic reference is to a dynamically-computed constant, the bootstrap method is not re-executed for these subsequent attempts. Because errors occurring on an initial attempt at resolution are thrown again on subsequent attempts, a class in one module that attempts to access, via resolution of a symbolic reference in its run-time constant pool, an unexported public type in a different module will always receive the same error indicating an inaccessible type (§5.4.4), even if the Java SE Platform API is used to dynamically export the public type’s package at some time after the class’s first attempt. Resolution of an unresolved symbolic reference to a dynamically-computed call site proceeds in accordance with the rules given in §5.4.3.6. Then:

  • If no error occurs during resolution of the symbolic reference, then resolution succeeds solely for the instruction in the class file that required resolution. This instruction necessarily has an opcode of invokedynamic.

    Subsequent attempts to resolve the symbolic reference by that instruction in the class file always succeed trivially and result in the same entity produced by the initial resolution. The bootstrap method is not re-executed for these subsequent attempts.

    The symbolic reference is still unresolved for all other instructions in the class file, of any opcode, which indicate the same entry in the run-time constant pool as the invokedynamic instruction above.

  • If an error occurs during resolution of the symbolic reference, then it is either (i) an instance of IncompatibleClassChangeError (or a subclass); (ii) an instance of Error (or a subclass) that arose from resolution or invocation of a bootstrap method; or (iii) an instance of LinkageError (or a subclass) that arose because class loading failed or a loader constraint was violated. The error must be thrown at a point in the program that (directly or indirectly) uses the symbolic reference.

    Subsequent attempts by the same instruction in the class file to resolve the symbolic reference always fail with the same error that was thrown as a result of the initial resolution attempt. The bootstrap method is not re-executed for these subsequent attempts.

    The symbolic reference is still unresolved for all other instructions in the class file, of any opcode, which indicate the same entry in the run-time constant pool as the invokedynamic instruction above. Certain of the instructions above require additional linking checks when resolving symbolic references. For instance, in order for a getfield instruction to successfully resolve the symbolic reference to the field on which it operates, it must not only complete the field resolution steps given in §5.4.3.2 but also check that the field is not static. If it is a static field, a linking exception must be thrown. Linking exceptions generated by checks that are specific to the execution of a particular Java Virtual Machine instruction are given in the description of that instruction and are not covered in this general discussion of resolution. Note that such exceptions, although described as part of the execution of Java Virtual Machine instructions rather than resolution, are still properly considered failures of resolution.

5.4.3.1 Class and Interface Resolution

To resolve an unresolved symbolic reference from D to a class or interface C denoted by N, the following steps are performed: 1. The defining class loader of D is used to create a class or interface denoted by N. This class or interface is C. The details of the process are given in §5.3.

+ Any exception that can be thrown as a result of failure of class or interface creation can thus be thrown as a result of failure of class and interface resolution. 2. If C is an array class and its element type is a reference type, then a symbolic reference to the class or interface representing the element type is resolved by invoking the algorithm in §5.4.3.1 recursively. 3. Finally, access control is applied for the access from D to C (§5.4.4). If steps 1 and 2 succeed but step 3 fails, C is still valid and usable. Nevertheless, resolution fails, and D is prohibited from accessing C.

5.4.3.2 Field Resolution

To resolve an unresolved symbolic reference from D to a field in a class or interface C, the symbolic reference to C given by the field reference must first be resolved (§5.4.3.1). Therefore, any exception that can be thrown as a result of failure of resolution of a class or interface reference can be thrown as a result of failure of field resolution. If the reference to C can be successfully resolved, an exception relating to the failure of resolution of the field reference itself can be thrown. When resolving a field reference, field resolution first attempts to look up the referenced field in C and its superclasses: 1. If C declares a field with the name and descriptor specified by the field reference, field lookup succeeds. The declared field is the result of the field lookup. 2. Otherwise, field lookup is applied recursively to the direct superinterfaces of the specified class or interface C. 3. Otherwise, if C has a superclass S, field lookup is applied recursively to S. 4. Otherwise, field lookup fails. Then, the result of field resolution is determined:

  • If field lookup failed, field resolution throws a NoSuchFieldError.

  • Otherwise, field lookup succeeded. Access control is applied for the access from D to the field which is the result of field lookup (§5.4.4). Then:

    • If access control failed, field resolution fails for the same reason.

    • Otherwise, access control succeeded. Loading constraints are imposed, as follows.

      Let <E, L1> be the class or interface in which the referenced field is actually declared. Let L2 be the defining loader of D. Given that the type of the referenced field is Tf: if Tf is not an array type, let T be Tf; otherwise, let T be the element type of Tf.

      The Java Virtual Machine imposes the loading constraint that TL1 = TL2.

      If imposing this constraint results in any loading constraints being violated (§5.3.4), then field resolution fails. Otherwise, field resolution succeeds.

5.4.3.3 Method Resolution

To resolve an unresolved symbolic reference from D to a method in a class C, the symbolic reference to C given by the method reference is first resolved (§5.4.3.1). Therefore, any exception that can be thrown as a result of failure of resolution of a class reference can be thrown as a result of failure of method resolution. If the reference to C can be successfully resolved, exceptions relating to the resolution of the method reference itself can be thrown. When resolving a method reference: 1. If C is an interface, method resolution throws an IncompatibleClassChangeError. 2. Otherwise, method resolution attempts to locate the referenced method in C and its superclasses:

  • If C declares exactly one method with the name specified by the method reference, and the declaration is a signature polymorphic method (§2.9.3), then method lookup succeeds. All the class names mentioned in the descriptor are resolved (§5.4.3.1).

    The resolved method is the signature polymorphic method declaration. It is not necessary for C to declare a method with the descriptor specified by the method reference.

  • Otherwise, if C declares a method with the name and descriptor specified by the method reference, method lookup succeeds.

  • Otherwise, if C has a superclass, step 2 of method resolution is recursively invoked on the direct superclass of C.

    1. Otherwise, method resolution attempts to locate the referenced method in the superinterfaces of the specified class C:

  • If the maximally-specific superinterface methods of C for the name and descriptor specified by the method reference include exactly one method that does not have its ACC_ABSTRACT flag set, then this method is chosen and method lookup succeeds.

  • Otherwise, if any superinterface of C declares a method with the name and descriptor specified by the method reference that has neither its ACC_PRIVATE flag nor its ACC_STATIC flag set, one of these is arbitrarily chosen and method lookup succeeds.

  • Otherwise, method lookup fails. A maximally-specific superinterface method of a class or interface C for a particular method name and descriptor is any method for which all of the following are true:

  • The method is declared in a superinterface (direct or indirect) of C.

  • The method is declared with the specified name and descriptor.

  • The method has neither its ACC_PRIVATE flag nor its ACC_STATIC flag set.

  • Where the method is declared in interface I, there exists no other maximally-specific superinterface method of C with the specified name and descriptor that is declared in a subinterface of I. The result of method resolution is determined as follows:

  • If method lookup failed, method resolution throws a NoSuchMethodError.

  • Otherwise, method lookup succeeded. Access control is applied for the access from D to the method which is the result of method lookup (§5.4.4). Then:

    • If access control failed, method resolution fails for the same reason.

    • Otherwise, access control succeeded. Loading constraints are imposed, as follows.

      Let <E, L1> be the class or interface in which the referenced method m is actually declared. Let L2 be the defining loader of D. Given that the return type of m is Tr, and that the formal parameter types of m are Tf1, …​, Tfn:

      If Tr is not an array type, let T0 be Tr; otherwise, let T0 be the element type of Tr.

      For i = 1 to n: If Tfi is not an array type, let Ti be Tfi; otherwise, let Ti be the element type of Tfi.

      The Java Virtual Machine imposes the loading constraints TiL1 = TiL2 for i = 0 to n.

      If imposing these constraints results in any loading constraints being violated (§5.3.4), then method resolution fails. Otherwise, method resolution succeeds. When resolution searches for a method in the class’s superinterfaces, the best outcome is to identify a maximally-specific non-abstract method. It is possible that this method will be chosen by method selection, so it is desirable to add class loader constraints for it. Otherwise, the result is nondeterministic. This is not new: The Java® Virtual Machine Specification has never identified exactly which method is chosen, and how "ties" should be broken. Prior to Java SE 8, this was mostly an unobservable distinction. However, beginning with Java SE 8, the set of interface methods is more heterogenous, so care must be taken to avoid problems with nondeterministic behavior. Thus:

  • Superinterface methods that are private and static are ignored by resolution. This is consistent with the Java programming language, where such interface methods are not inherited.

  • Any behavior controlled by the resolved method should not depend on whether the method is abstract or not. Note that if the result of resolution is an abstract method, the referenced class C may be non-abstract. Requiring C to be abstract would conflict with the nondeterministic choice of superinterface methods. Instead, resolution assumes that the run time class of the invoked object has a concrete implementation of the method.

5.4.3.4 Interface Method Resolution

To resolve an unresolved symbolic reference from D to an interface method in an interface C, the symbolic reference to C given by the interface method reference is first resolved (§5.4.3.1). Therefore, any exception that can be thrown as a result of failure of resolution of an interface reference can be thrown as a result of failure of interface method resolution. If the reference to C can be successfully resolved, exceptions relating to the resolution of the interface method reference itself can be thrown. When resolving an interface method reference: 1. If C is not an interface, interface method resolution throws an IncompatibleClassChangeError. 2. Otherwise, if C declares a method with the name and descriptor specified by the interface method reference, method lookup succeeds. 3. Otherwise, if the class Object declares a method with the name and descriptor specified by the interface method reference, which has its ACC_PUBLIC flag set and does not have its ACC_STATIC flag set, method lookup succeeds. 4. Otherwise, if the maximally-specific superinterface methods (§5.4.3.3) of C for the name and descriptor specified by the method reference include exactly one method that does not have its ACC_ABSTRACT flag set, then this method is chosen and method lookup succeeds. 5. Otherwise, if any superinterface of C declares a method with the name and descriptor specified by the method reference that has neither its ACC_PRIVATE flag nor its ACC_STATIC flag set, one of these is arbitrarily chosen and method lookup succeeds. 6. Otherwise, method lookup fails. The result of interface method resolution is determined as follows:

  • If method lookup failed, interface method resolution throws a NoSuchMethodError.

  • Otherwise, method lookup succeeded. Access control is applied for the access from D to the method which is the result of method lookup (§5.4.4). Then:

    • If access control failed, interface method resolution fails for the same reason.

    • Otherwise, access control succeeded. Loading constraints are imposed, as follows.

      Let <E, L1> be the class or interface in which the referenced interface method m is actually declared. Let L2 be the defining loader of D. Given that the return type of m is Tr, and that the formal parameter types of m are Tf1, …​, Tfn:

      If Tr is not an array type, let T0 be Tr; otherwise, let T0 be the element type of Tr.

      For i = 1 to n: If Tfi is not an array type, let Ti be Tfi; otherwise, let Ti be the element type of Tfi.

      The Java Virtual Machine imposes the loading constraints TiL1 = TiL2 for i = 0 to n.

      If imposing these constraints results in any loading constraints being violated (§5.3.4), then interface method resolution fails. Otherwise, interface method resolution succeeds. Access control is necessary because interface method resolution may pick a private method of interface C. (Prior to Java SE 8, the result of interface method resolution could be a non-public method of class Object or a static method of class Object; such results were not consistent with the inheritance model of the Java programming language, and are disallowed in Java SE 8 and above.)

5.4.3.5 Method Type and Method Handle Resolution

To resolve an unresolved symbolic reference to a method type, it is as if resolution occurs of unresolved symbolic references to classes and interfaces (§5.4.3.1) whose names correspond to the types given in the method descriptor (§4.3.3). Any exception that can be thrown as a result of failure of resolution of a class reference can thus be thrown as a result of failure of method type resolution. The result of successful method type resolution is a reference to an instance of java.lang.invoke.MethodType which represents the method descriptor. Method type resolution occurs regardless of whether the run-time constant pool actually contains symbolic references to classes and interfaces indicated in the method descriptor. Also, the resolution is deemed to occur on unresolved symbolic references, so a failure to resolve one method type will not necessarily lead to a later failure to resolve another method type with the same textual method descriptor, if suitable classes and interfaces can be loaded by the later time. Resolution of an unresolved symbolic reference to a method handle is more complicated. Each method handle resolved by the Java Virtual Machine has an equivalent instruction sequence called its bytecode behavior, indicated by the method handle’s kind. The integer values and descriptions of the nine kinds of method handle are given in Table 5.4.3.5-A. Symbolic references by an instruction sequence to fields or methods are indicated by C.x:T, where x and T are the name and descriptor (§4.3.2, §4.3.3) of the field or method, and C is the class or interface in which the field or method is to be found. .Table 5.4.3.5-A. Bytecode Behaviors for Method Handles

Kind

Description

Interpretation

1

REF_getField

getfield C.f:T

2

REF_getStatic

getstatic C.f:T

3

REF_putField

putfield C.f:T

4

REF_putStatic

putstatic C.f:T

5

REF_invokeVirtual

invokevirtual C.m:(A*)T

6

REF_invokeStatic

invokestatic C.m:(A*)T

7

REF_invokeSpecial

invokespecial C.m:(A*)T

8

REF_newInvokeSpecial

new C; dup; invokespecial C.<init>:(A*)V

9

REF_invokeInterface

invokeinterface C.m:(A*)T

Let MH be the symbolic reference to a method handle (§5.1) being resolved. Also:

  • Let R be the symbolic reference to the field or method contained within MH.

    R is derived from the CONSTANT_Fieldref, CONSTANT_Methodref, or CONSTANT_InterfaceMethodref structure referred to by the reference_index item of the CONSTANT_MethodHandle from which MH is derived.

    For example, R is a symbolic reference to C . f for bytecode behavior of kind 1, and a symbolic reference to C . <init> for bytecode behavior of kind 8.

    If MH’s bytecode behavior is kind 7 (REF_invokeSpecial), then C must be the current class or interface, a superclass of the current class, a direct superinterface of the current class or interface, or Object.

  • Let T be the type of the field referenced by R, or the return type of the method referenced by R. Let A* be the sequence (perhaps empty) of parameter types of the method referenced by R.

    T and A* are derived from the CONSTANT_NameAndType structure referred to by the name_and_type_index item in the CONSTANT_Fieldref, CONSTANT_Methodref, or CONSTANT_InterfaceMethodref structure from which R is derived. To resolve MH, all symbolic references to classes, interfaces, fields, and methods in MH’s bytecode behavior are resolved, using the following four steps: 1. R is resolved. This occurs as if by field resolution (§5.4.3.2) when MH’s bytecode behavior is kind 1, 2, 3, or 4, and as if by method resolution (§5.4.3.3) when MH’s bytecode behavior is kind 5, 6, 7, or 8, and as if by interface method resolution (§5.4.3.4) when MH’s bytecode behavior is kind 9. 2. The following constraints apply to the result of resolving R. These constraints correspond to those that would be enforced during verification or execution of the instruction sequence for the relevant bytecode behavior.

  • If MH’s bytecode behavior is kind 8 (REF_newInvokeSpecial), then R must resolve to an instance initialization method declared in class C.

  • If R resolves to a protected member, then the following rules apply depending on the kind of MH’s bytecode behavior:

    • For kinds 1, 3, and 5 (REF_getField, REF_putField, and REF_invokeVirtual): If C.f or C.m resolved to a protected field or method, and C is in a different run-time package than the current class, then C must be assignable to the current class.

    • For kind 8 (REF_newInvokeSpecial): If C . <init> resolved to a protected method, then C must be declared in the same run-time package as the current class.

  • R must resolve to a static or non-static member depending on the kind of MH’s bytecode behavior:

    • For kinds 1, 3, 5, 7, and 9 (REF_getField, REF_putField, REF_invokeVirtual, REF_invokeSpecial, and REF_invokeInterface): C.f or C.m must resolve to a non-static field or method.

    • For kinds 2, 4, and 6 (REF_getStatic, REF_putStatic, and REF_invokeStatic): C.f or C.m must resolve to a static field or method.

      1. Resolution occurs as if of unresolved symbolic references to classes and interfaces whose names correspond to each type in A*, and to the type T, in that order.

      2. A reference to an instance of java.lang.invoke.MethodType is obtained as if by resolution of an unresolved symbolic reference to a method type that contains the method descriptor specified in Table 5.4.3.5-B for the kind of MH. It is as if the symbolic reference to a method handle contains a symbolic reference to the method type that the resolved method handle will eventually have. The detailed structure of the method type is obtained by inspecting Table 5.4.3.5-B. .Table 5.4.3.5-B. Method Descriptors for Method Handles

Kind

Description

Method descriptor

1

REF_getField

©T

2

REF_getStatic

()T

3

REF_putField

(C,T)V

4

REF_putStatic

(T)V

5

REF_invokeVirtual

(C,A*)T

6

REF_invokeStatic

(A*)T

7

REF_invokeSpecial

(C,A*)T

8

REF_newInvokeSpecial

(A*)C

9

REF_invokeInterface

(C,A*)T

In steps 1, 3, and 4, any exception that can be thrown as a result of failure of resolution of a symbolic reference to a class, interface, field, or method can be thrown as a result of failure of method handle resolution. In step 2, any failure due to the specified constraints causes a failure of method handle resolution due to an IllegalAccessError. The intent is that resolving a method handle can be done in exactly the same circumstances that the Java Virtual Machine would successfully verify and resolve the symbolic references in the bytecode behavior. In particular, method handles to private, protected, and static members can be created in exactly those classes for which the corresponding normal accesses are legal. The result of successful method handle resolution is a reference to an instance of java.lang.invoke.MethodHandle which represents the method handle MH. The type descriptor of this java.lang.invoke.MethodHandle instance is the java.lang.invoke.MethodType instance produced in the third step of method handle resolution above. The type descriptor of a method handle is such that a valid call to invokeExact in java.lang.invoke.MethodHandle on the method handle has exactly the same stack effects as the bytecode behavior. Calling this method handle on a valid set of arguments has exactly the same effect and returns the same result (if any) as the corresponding bytecode behavior. If the method referenced by R has the ACC_VARARGS flag set (§4.6), then the java.lang.invoke.MethodHandle instance is a variable arity method handle; otherwise, it is a fixed arity method handle. A variable arity method handle performs argument list boxing (JLS §15.12.4.2) when invoked via invoke, while its behavior with respect to invokeExact is as if the ACC_VARARGS flag were not set. Method handle resolution throws an IncompatibleClassChangeError if the method referenced by R has the ACC_VARARGS flag set and either A* is an empty sequence or the last parameter type in A* is not an array type. That is, creation of a variable arity method handle fails. An implementation of the Java Virtual Machine is not required to intern method types or method handles. That is, two distinct symbolic references to method types or method handles which are structurally identical might not resolve to the same instance of java.lang.invoke.MethodType or java.lang.invoke.MethodHandle respectively. The java.lang.invoke.MethodHandles class in the Java SE Platform API allows creation of method handles with no bytecode behavior. Their behavior is defined by the method of java.lang.invoke.MethodHandles that creates them. For example, a method handle may, when invoked, first apply transformations to its argument values, then supply the transformed values to the invocation of another method handle, then apply a transformation to the value returned from that invocation, then return the transformed value as its own result.

5.4.3.6 Dynamically-Computed Constant and Call Site Resolution

To resolve an unresolved symbolic reference R to a dynamically-computed constant or call site, there are three tasks. First, R is examined to determine which code will serve as its bootstrap method, and which arguments will be passed to that code. Second, the arguments are packaged into an array and the bootstrap method is invoked. Third, the result of the bootstrap method is validated, and used as the result of resolution. The first task involves the following steps: 1. R gives a symbolic reference to a bootstrap method handle. The bootstrap method handle is resolved (§5.4.3.5) to obtain a reference to an instance of java.lang.invoke.MethodHandle.

+ Any exception that can be thrown as a result of failure of resolution of a symbolic reference to a method handle can be thrown in this step.

+ If R is a symbolic reference to a dynamically-computed constant, then let D be the type descriptor of the bootstrap method handle. (That is, D is a reference to an instance of java.lang.invoke.MethodType.) The first parameter type indicated by D must be java.lang.invoke.MethodHandles.Lookup, or else resolution fails with a BootstrapMethodError. For historical reasons, the bootstrap method handle for a dynamically-computed call site is not similarly constrained.

+ 2. If R is a symbolic reference to a dynamically-computed constant, then it gives a field descriptor.

+ If the field descriptor indicates a primitive type, then a reference to the pre-defined Class object representing that type is obtained (see the method isPrimitive in class Class).

+ Otherwise, the field descriptor indicates a class or interface type, or an array type. A reference to the Class object representing the type indicated by the field descriptor is obtained, as if by resolution of an unresolved symbolic reference to a class or interface (§5.4.3.1) whose name corresponds to the type indicated by the field descriptor.

+ Any exception that can be thrown as a result of failure of resolution of a symbolic reference to a class or interface can be thrown in this step. 3. If R is a symbolic reference to a dynamically-computed call site, then it gives a method descriptor.

+ A reference to an instance of java.lang.invoke.MethodType is obtained, as if by resolution of an unresolved symbolic reference to a method type (§5.4.3.5) with the same parameter and return types as the method descriptor.

+ Any exception that can be thrown as a result of failure of resolution of a symbolic reference to a method type can be thrown in this step. 4. R gives zero or more static arguments, which communicate application-specific metadata to the bootstrap method. Each static argument A is resolved, in the order given by R, as follows:

  • If A is a string constant, then a reference to its instance of class String is obtained.

  • If A is a numeric constant, then a reference to an instance of java.lang.invoke.MethodHandle is obtained by the following procedure:

    1. Let v be the value of the numeric constant, and let T be a field descriptor which corresponds to the type of the numeric constant.

    2. Let MH be a method handle produced as if by invocation of the identity method of java.lang.invoke.MethodHandles with an argument representing the class Object.

    3. A reference to an instance of java.lang.invoke.MethodHandle is obtained as if by the invocation MH.invoke(v) with method descriptor (T)Ljava/lang/Object;.

  • If A is a symbolic reference to a dynamically-computed constant with a field descriptor indicating a primitive type T, then A is resolved, producing a primitive value v. Given v and T, a reference is obtained to an instance of java.lang.invoke.MethodHandle according to the procedure specified above for numeric constants.

  • If A is any other kind of symbolic reference, then the result is the result of resolving A. Among the symbolic references in the run-time constant pool, symbolic references to dynamically-computed constants are special because they are derived from constant_pool entries that can syntactically refer to themselves via the BootstrapMethods attribute (§4.7.23). However, the Java Virtual Machine does not support resolving a symbolic reference to a dynamically-computed constant that depends on itself (that is, as a static argument to its own bootstrap method). Accordingly, when both R and A are symbolic references to dynamically-computed constants, if A is the same as R or A gives a static argument that (directly or indirectly) references R, then resolution fails with a StackOverflowError at the point where re-resolution of R would be required. Unlike class initialization (§5.5), where cycles are allowed between uninitialized classes, resolution does not allow cycles in symbolic references to dynamically-computed constants. If an implementation of resolution makes recursive use of a stack, then a StackOverflowError will occur naturally. If not, the implementation is required to detect the cycle rather than, say, looping infinitely or returning a default value for the dynamically-computed constant. A similar cycle may arise if the body of a bootstrap method makes reference to a dynamically-computed constant currently being resolved. This has always been possible for invokedynamic bootstraps, and does not require special treatment in resolution; the recursive invokeWithArguments calls will naturally lead to a StackOverflowError. Any exception that can be thrown as a result of failure of resolution of a symbolic reference can be thrown in this step. The second task, to invoke the bootstrap method handle, involves the following steps:

    1. An array is allocated with component type Object and length n+3, where n is the number of static arguments given by R (n ≥ 0).

      The zeroth component of the array is set to a reference to an instance of java.lang.invoke.MethodHandles.Lookup for the class in which R occurs, produced as if by invocation of the lookup method of java.lang.invoke.MethodHandles.

      The first component of the array is set to a reference to an instance of String that denotes N, the unqualified name given by R.

      The second component of the array is set to the reference to an instance of Class or java.lang.invoke.MethodType that was obtained earlier for the field descriptor or method descriptor given by R.

      Subsequent components of the array are set to the references that were obtained earlier from resolving R’s static arguments, if any. The references appear in the array in the same order as the corresponding static arguments are given by R.

      A Java Virtual Machine implementation may be able to skip allocation of the array and, without any change in observable behavior, pass the arguments directly to the bootstrap method.

    2. The bootstrap method handle is invoked, as if by the invocation BMH.invokeWithArguments(args), where BMH is the bootstrap method handle and args is the array allocated above.

      Due to the behavior of the invokeWithArguments method of java.lang.invoke.MethodHandle, the type descriptor of the bootstrap method handle need not exactly match the run-time types of the arguments. For example, the second parameter type of the bootstrap method handle (corresponding to the unqualified name given in the first component of the array above) could be Object instead of String. If the bootstrap method handle is variable arity, then some or all of the arguments may be collected into a trailing array parameter.

      The invocation occurs within a thread that is attempting resolution of this symbolic reference. If there are several such threads, the bootstrap method handle may be invoked concurrently. Bootstrap methods which access global application data should take the usual precautions against race conditions.

      If the invocation fails by throwing an instance of Error or a subclass of Error, resolution fails with that exception.

      If the invocation fails by throwing an exception that is not an instance of Error or a subclass of Error, resolution fails with a BootstrapMethodError whose cause is the thrown exception.

      If several threads concurrently invoke the bootstrap method handle for this symbolic reference, the Java Virtual Machine chooses the result of one invocation and installs it visibly to all threads. Any other bootstrap methods executing for this symbolic reference are allowed to complete, but their results are ignored. The third task, to validate the reference, o, produced by invocation of the bootstrap method handle, is as follows:

  • If R is a symbolic reference to a dynamically-computed constant, then o is converted to type T, the type indicated by the field descriptor given by R.

    o’s conversion occurs as if by the invocation MH.invoke(o) with method descriptor (Ljava/lang/Object;)T, where MH is a method handle produced as if by invocation of the identity method of java.lang.invoke.MethodHandles with an argument representing the class Object.

    The result of o’s conversion is the result of resolution.

    If the conversion fails by throwing a NullPointerException or a ClassCastException, resolution fails with a BootstrapMethodError.

  • If R is a symbolic reference to a dynamically-computed call site, then o is the result of resolution if it has all of the following properties:

    • o is not null.

    • o is an instance of java.lang.invoke.CallSite or a subclass of java.lang.invoke.CallSite.

    • The type of the java.lang.invoke.CallSite is semantically equal to the method descriptor given by R. If o does not have these properties, resolution fails with a BootstrapMethodError. Many of the steps above perform computations "as if by invocation" of certain methods. In each case, the invocation behavior is given in detail by the specifications for invokestatic and invokevirtual. The invocation occurs in the thread and from the class that is attempting resolution of the symbolic reference R. However, no corresponding method references are required to appear in the run-time constant pool, no particular method’s operand stack is necessarily used, and the value of the max_stack item of any method’s Code attribute is not enforced for the invocation. If several threads attempt resolution of R at the same time, the bootstrap method may be invoked concurrently. Therefore, bootstrap methods which access global application data must take precautions against race conditions.

贡献翻译,请加 QQ: 840750575    点击这里给我发消息
数码
沪ICP备19006215号-4