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 
  30 import vm.mlvm.meth.share.Argument;
  31 import vm.mlvm.meth.share.Arguments;
  32 import vm.mlvm.meth.share.SimpleOpMethodHandles;
  33 import vm.mlvm.share.Env;
  34 
  35 public class MHThrowCatchTFPair extends MHTFPair {
  36 
  37     private final String id;
  38     private final Argument testArg;
  39     private final Object testValue2;
  40     private final boolean testEq;
  41     private final Throwable _exception;
  42 
  43     private class ThrowTF extends MHDropTF {
  44 
  45         public ThrowTF(MHCall outboundCall) {
  46             super(outboundCall, 0, new Argument[] { testArg });
  47         }
  48 
  49         @Override
  50         protected MethodHandle computeInboundMH(MethodHandle targetMH) {
  51             try {
  52                 Argument testArg = MHThrowCatchTFPair.this.testArg;
  53 
  54                 MethodType targetType = targetMH.type().insertParameterTypes(0, testArg.getType());
  55 
  56                 MHMacroTF mTF = new MHMacroTF("throwCatch throw part");
  57                 mTF.addOutboundCall(getTargetCall());
  58 /*
  59                 MHCall testCall =
  60                     mTF.addTransformation(new MHInsertTF(
  61                            mTF.addTransformation(new MHExplicitCastTF(
  62                                mTF.addTransformation(new MHEqualityTestTF(testArg)),
  63                                boolean.class, new Class<?>[] { testArg.getType(), testArg.getType() })),
  64                     0, new Argument[] { testArg }, false));
  65 */
  66                 MethodHandle testMH = MethodHandles.insertArguments(
  67                         MethodHandles.explicitCastArguments(
  68                                 SimpleOpMethodHandles.eqMH(),
  69                                 MethodType.methodType(boolean.class, testArg.getType(), testArg.getType())),
  70                         0, testArg.getValue());
  71 
  72                 MethodHandle normalBranchMH = MethodHandles.dropArguments(targetMH, 0, testArg.getType());
  73 
  74                 MethodHandle throwingBranchMH =
  75                     MethodHandles.dropArguments(
  76                             MethodHandles.insertArguments(
  77                                     MethodHandles.throwException(targetType.returnType(), _exception.getClass()),
  78                             0, _exception),
  79                     0, targetType.parameterArray());
  80 
  81                 MethodHandle thenMH, elseMH;
  82                 if ( MHThrowCatchTFPair.this.testEq ) {
  83                     thenMH = throwingBranchMH;
  84                     elseMH = normalBranchMH;
  85                 } else {
  86                     testMH = MethodHandles.filterReturnValue(testMH, SimpleOpMethodHandles.notMH());
  87                     elseMH = throwingBranchMH;
  88                     thenMH = normalBranchMH;
  89                 }
  90 
  91                 Env.traceDebug("ThrowCatchTFPair: targetMH=%s; testMH=%s; thenMH=%s; elseMH=%s",
  92                                targetMH.type(), testMH.type(), thenMH.type(), elseMH.type());
  93 
  94                 return MethodHandles.guardWithTest(testMH, thenMH, elseMH);
  95             } catch ( Throwable t ) {
  96                 throw (IllegalArgumentException) (new IllegalArgumentException("Can't create throw/catch TF")).initCause(t);
  97             }
  98         }
  99     }
 100 
 101     private class CatchTF extends MHInsertTF {
 102 
 103         public CatchTF(MHCall target, int argIdx) {
 104             super(target, argIdx, new Argument[] { testArg }, true);
 105         }
 106 
 107         @Override
 108         protected MethodHandle computeInboundMH(MethodHandle targetMH) {
 109             try {
 110                 MethodHandle catchTargetMH = MethodHandles.insertArguments(targetMH, this.pos, MHThrowCatchTFPair.this.testArg.getValue());
 111                 MethodHandle catchHandlerMH = MethodHandles.dropArguments(
 112                         MethodHandles.insertArguments(targetMH, this.pos, MHThrowCatchTFPair.this.testValue2),
 113                         0, _exception.getClass());
 114 
 115                 return MethodHandles.catchException(catchTargetMH, _exception.getClass(), catchHandlerMH);
 116             } catch ( Throwable t ) {
 117                 IllegalArgumentException e = new IllegalArgumentException("Can't create a transformation");
 118                 e.initCause(t);
 119                 throw e;
 120             }
 121         }
 122     }
 123     public MHThrowCatchTFPair(MHCall outboundTarget, Argument testArg, Object testValue2, boolean testEq, Throwable exc) {
 124         super(outboundTarget);
 125         this.id = "ThrowCatch_" + hashCode();
 126 
 127         this.testArg = testArg.clone();
 128         this.testArg.setPreserved(true);
 129         this.testArg.setTag(this.id);
 130 
 131         this.testValue2 = testValue2;
 132         this.testEq = testEq;
 133         _exception = exc;
 134     }
 135 
 136     @Override
 137     public MHTF getOutboundTF() {
 138         return new ThrowTF(this.outboundTarget);
 139     }
 140 
 141     @Override
 142     public MHTF getInboundTF(MHCall inboundTarget) {
 143         int[] tagged = Arguments.findTag(inboundTarget.getArgs(), this.id);
 144 
 145         if ( tagged.length != 1 ) {
 146             throw new IllegalArgumentException("Can't find exactly one argument tagged " + this.id
 147                               + " from inner transformation (found indexes: " + tagged + ")");
 148         }
 149 
 150         return new CatchTF(inboundTarget, tagged[0]);
 151     }
 152 
 153 }