1 /*
2  * Copyright (c) 2011, 2018, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package vm.mlvm.meth.share.transform.v2;
25 
26 import java.lang.invoke.MethodHandle;
27 import java.lang.invoke.MethodHandles;
28 import java.lang.invoke.MethodType;
29 import java.lang.invoke.WrongMethodTypeException;
30 import java.util.Arrays;
31 
32 import nsk.share.test.LazyIntArrayToString;
33 import vm.mlvm.meth.share.Argument;
34 import vm.mlvm.meth.share.MHUtils;
35 import vm.mlvm.share.Env;
36 
37 public class MHPermuteTF extends MHBasicUnaryTF {
38 
39     private final int[] _reorderArray;
40     private final MethodType _sourceMT;
41 
MHPermuteTF(MHCall target, MethodType sourceMT, int[] reorderArray)42     public MHPermuteTF(MHCall target, MethodType sourceMT, int[] reorderArray) {
43         super(target);
44         _reorderArray = reorderArray;
45         _sourceMT = sourceMT;
46     }
47 
MHPermuteTF(MHCall target, int[] reorderArray)48     public MHPermuteTF(MHCall target, int[] reorderArray) {
49         this(target, getPermutedMT(target.getTargetMH().type(), reorderArray), reorderArray);
50     }
51 
52     @Override
check(Argument[] targetArgs)53     protected void check(Argument[] targetArgs) throws IllegalArgumentException {
54         super.check(targetArgs);
55 
56         if ( _sourceMT.parameterCount() < _reorderArray.length ) {
57             throw new WrongMethodTypeException("reorderArray requires at least "
58                                              + _reorderArray.length + " target arguments, but only "
59                                              + _sourceMT.parameterCount() + " are given");
60         }
61 
62         for ( int i = 0; i < _reorderArray.length; i++ ) {
63             MHUtils.assertAssignableType("reorderArray element " + i,
64                     targetArgs[i].getType(),
65                     _sourceMT.parameterType(_reorderArray[i]));
66         }
67     }
68 
69     @Override
computeInboundMH(MethodHandle targetMH)70     protected MethodHandle computeInboundMH(MethodHandle targetMH) {
71         MethodHandle r = MethodHandles.permuteArguments(targetMH, _sourceMT, _reorderArray);
72         Env.traceDebug("permute: inType=%s; targetType=%s; reorder=%s",
73                        r.type(), targetMH.type(), new LazyIntArrayToString(_reorderArray));
74         return r;
75     }
76 
77     @Override
computeInboundArgs(Argument[] targetArgs)78     protected Argument[] computeInboundArgs(Argument[] targetArgs) {
79         Argument[] resultArgs = new Argument[_sourceMT.parameterCount()];
80 
81         for ( int i = 0; i < targetArgs.length; i++ ) {
82             resultArgs[_reorderArray[i]] = targetArgs[i];
83         }
84 
85         for ( int i = 0; i < resultArgs.length; i++ ) {
86             if ( resultArgs[i] == null ) {
87                 resultArgs[i] = new Argument(_sourceMT.parameterType(i), null);
88             }
89         }
90 
91         return resultArgs;
92     }
93 
94     @Override
getName()95     protected String getName() {
96         return "permuteArguments";
97     }
98 
99     @Override
getDescription()100     protected String getDescription() {
101         return "sourceMT=" + _sourceMT + "; reorder=" + Arrays.toString(_reorderArray);
102     }
103 
getPermutedMT(MethodType targetMT, int[] reorderArray)104     public static MethodType getPermutedMT(MethodType targetMT, int[] reorderArray) {
105         int srcParamCount = 0;
106         for ( int t = 0; t < reorderArray.length; t++ )
107             srcParamCount = Math.max(srcParamCount, reorderArray[t] + 1);
108 
109         Class<?>[] paramTypes = new Class<?>[srcParamCount];
110 
111         for ( int t = 0; t < reorderArray.length; t++ )
112             paramTypes[reorderArray[t]] = targetMT.parameterType(t);
113 
114         for ( int s = 0; s < paramTypes.length; s++ )
115             if ( paramTypes[s] == null )
116                     throw new IllegalArgumentException("Type of parameter #" + s + " is not defined");
117 
118         return MethodType.methodType(targetMT.returnType(), paramTypes);
119     }
120 
getIdentityPermuteArray(int argCount)121     public static int[] getIdentityPermuteArray(int argCount) {
122         int[] result = new int[argCount];
123         for ( int i = 0; i < argCount; i++ )
124             result[i] = i;
125         return result;
126     }
127 
moveArgsInPermuteArray(int[] array, int oldPos, int count, int newPos)128     public static int[] moveArgsInPermuteArray(int[] array, int oldPos, int count, int newPos) {
129         if ( newPos == oldPos )
130             return array;
131 
132         int[] result = new int[array.length];
133 
134         if ( newPos < oldPos ) {
135             System.arraycopy(array, 0, result, 0, newPos);
136             System.arraycopy(array, newPos, result, newPos + count, oldPos - newPos);
137             System.arraycopy(array, oldPos + count, result, oldPos + count, array.length - oldPos - count);
138         } else {
139             System.arraycopy(array, 0, result, 0, oldPos);
140             System.arraycopy(array, oldPos + count, result, oldPos, newPos - oldPos - count);
141             System.arraycopy(array, newPos + count, result, newPos + count, array.length - newPos - count);
142         }
143         System.arraycopy(array, oldPos, result, newPos, count);
144 
145         return result;
146     }
147 }
148