@Override
  public GuardedInvocation getGuardedInvocation(
      final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
    final LinkRequest request =
        linkRequest.withoutRuntimeContext(); // Nashorn has no runtime context
    final Object self = request.getReceiver();
    if (self.getClass() != StaticClass.class) {
      return null;
    }
    final Class<?> receiverClass = ((StaticClass) self).getRepresentedClass();

    Bootstrap.checkReflectionAccess(receiverClass, true);
    final CallSiteDescriptor desc = request.getCallSiteDescriptor();
    // We intercept "new" on StaticClass instances to provide additional capabilities
    if ("new".equals(desc.getNameToken(CallSiteDescriptor.OPERATOR))) {
      if (!Modifier.isPublic(receiverClass.getModifiers())) {
        throw ECMAErrors.typeError("new.on.nonpublic.javatype", receiverClass.getName());
      }

      // make sure new is on accessible Class
      Context.checkPackageAccess(receiverClass);

      // Is the class abstract? (This includes interfaces.)
      if (NashornLinker.isAbstractClass(receiverClass)) {
        // Change this link request into a link request on the adapter class.
        final Object[] args = request.getArguments();
        args[0] =
            JavaAdapterFactory.getAdapterClassFor(
                new Class<?>[] {receiverClass},
                null,
                linkRequest.getCallSiteDescriptor().getLookup());
        final LinkRequest adapterRequest =
            request.replaceArguments(request.getCallSiteDescriptor(), args);
        final GuardedInvocation gi =
            checkNullConstructor(delegate(linkerServices, adapterRequest), receiverClass);
        // Finally, modify the guard to test for the original abstract class.
        return gi.replaceMethods(gi.getInvocation(), Guards.getIdentityGuard(self));
      }
      // If the class was not abstract, just delegate linking to the standard StaticClass linker.
      // Make an
      // additional check to ensure we have a constructor. We could just fall through to the next
      // "return"
      // statement, except we also insert a call to checkNullConstructor() which throws an
      // ECMAScript TypeError
      // with a more intuitive message when no suitable constructor is found.
      return checkNullConstructor(delegate(linkerServices, request), receiverClass);
    }
    // In case this was not a "new" operation, just delegate to the the standard StaticClass linker.
    return delegate(linkerServices, request);
  }
Example #2
0
 /**
  * Takes a guarded invocation, and ensures its method and guard conform to the type of the call
  * descriptor, using all type conversions allowed by the linker's services. This method is used by
  * Nashorn's linkers as a last step before returning guarded invocations. Most of the code used to
  * produce the guarded invocations does not make an effort to coordinate types of the methods, and
  * so a final type adjustment before a guarded invocation is returned to the aggregating linker is
  * the responsibility of the linkers themselves.
  *
  * @param inv the guarded invocation that needs to be type-converted. Can be null.
  * @param linkerServices the linker services object providing the type conversions.
  * @param desc the call site descriptor to whose method type the invocation needs to conform.
  * @return the type-converted guarded invocation. If input is null, null is returned. If the input
  *     invocation already conforms to the requested type, it is returned unchanged.
  */
 static GuardedInvocation asTypeSafeReturn(
     final GuardedInvocation inv,
     final LinkerServices linkerServices,
     final CallSiteDescriptor desc) {
   return inv == null ? null : inv.asTypeSafeReturn(linkerServices, desc.getMethodType());
 }