1 /*
  2  * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.internal.reflect;
 27 
 28 import jdk.internal.vm.annotation.ForceInline;
 29 import jdk.internal.vm.annotation.Hidden;
 30 
 31 import java.lang.invoke.MethodHandle;
 32 import java.lang.invoke.WrongMethodTypeException;
 33 import java.lang.reflect.Constructor;
 34 import java.lang.reflect.InvocationTargetException;
 35 
 36 import static jdk.internal.reflect.MethodHandleAccessorFactory.SPECIALIZED_PARAM_COUNT;
 37 
 38 class DirectConstructorHandleAccessor extends ConstructorAccessorImpl {
 39     static ConstructorAccessorImpl constructorAccessor(Constructor<?> ctor, MethodHandle target) {
 40         return new DirectConstructorHandleAccessor(ctor, target);
 41     }
 42 
 43     static ConstructorAccessorImpl nativeAccessor(Constructor<?> ctor) {
 44         return new NativeAccessor(ctor);
 45     }
 46 
 47     private static final int PARAM_COUNT_MASK = 0x00FF;
 48     private static final int NONZERO_BIT = 0x8000_0000;
 49 
 50     private final int paramFlags;
 51     private final MethodHandle target;
 52 
 53     DirectConstructorHandleAccessor(Constructor<?> ctor, MethodHandle target) {
 54         this.paramFlags = (ctor.getParameterCount() & PARAM_COUNT_MASK) | NONZERO_BIT;
 55         this.target = target;
 56     }
 57 
 58     @Override
 59     public Object newInstance(Object[] args) throws InstantiationException, InvocationTargetException {
 60         int argc = args != null ? args.length : 0;
 61         // only check argument count for specialized forms
 62         int paramCount = paramFlags & PARAM_COUNT_MASK;
 63         if (paramCount <= SPECIALIZED_PARAM_COUNT && argc != paramCount) {
 64             throw new IllegalArgumentException("wrong number of arguments: " + argc + " expected: " + paramCount);
 65         }
 66         try {
 67             return invokeImpl(args);
 68         } catch (ClassCastException|WrongMethodTypeException e) {
 69             if (isIllegalArgument(e))
 70                 throw new IllegalArgumentException("argument type mismatch", e);
 71             else
 72                 throw new InvocationTargetException(e);
 73         } catch (NullPointerException e) {
 74             if (isIllegalArgument(e))
 75                 throw new IllegalArgumentException(e);
 76             else
 77                 throw new InvocationTargetException(e);
 78         } catch (Throwable e) {
 79             throw new InvocationTargetException(e);
 80         }
 81     }
 82 
 83     private boolean isIllegalArgument(RuntimeException ex) {
 84         return AccessorUtils.isIllegalArgument(DirectConstructorHandleAccessor.class, ex);
 85     }
 86 
 87     @Hidden
 88     @ForceInline
 89     Object invokeImpl(Object[] args) throws Throwable {
 90         return switch (paramFlags & PARAM_COUNT_MASK) {
 91             case 0 -> target.invokeExact();
 92             case 1 -> target.invokeExact(args[0]);
 93             case 2 -> target.invokeExact(args[0], args[1]);
 94             case 3 -> target.invokeExact(args[0], args[1], args[2]);
 95             default -> target.invokeExact(args);
 96         };
 97     }
 98 
 99     /**
100      * Invoke the constructor via native VM reflection
101      */
102     static class NativeAccessor extends ConstructorAccessorImpl {
103         private final Constructor<?> ctor;
104         NativeAccessor(Constructor<?> ctor) {
105             this.ctor = ctor;
106         }
107 
108         @Override
109         public Object newInstance(Object[] args) throws InstantiationException, InvocationTargetException {
110             return newInstance0(ctor, args);
111         }
112         private static native Object newInstance0(Constructor<?> c, Object[] args)
113                     throws InstantiationException, InvocationTargetException;
114     }
115 }