/****************************************************************************** * Copyright (c) 2002 - 2014 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *****************************************************************************/ package com.ibm.wala.shrikeBT; import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import com.ibm.wala.shrikeCT.BootstrapMethodsReader.BootstrapMethod; public class InvokeDynamicInstruction extends Instruction implements IInvokeInstruction { protected BootstrapMethod bootstrap; protected String methodName; protected String methodType; public InvokeDynamicInstruction(short opcode, BootstrapMethod bootstrap, String methodName, String methodType) { super(opcode); this.bootstrap = bootstrap; this.methodName = methodName; this.methodType = methodType; } ConstantPoolReader getLazyConstantPool() { return null; } @Override public boolean isPEI() { return true; } @Override public Dispatch getInvocationCode() { int invokeType = getBootstrap().invokeType(); switch (invokeType) { case 5: return Dispatch.VIRTUAL; case 6: return Dispatch.STATIC; case 7: return Dispatch.SPECIAL; case 9: return Dispatch.INTERFACE; default: throw new Error("unexpected dynamic invoke type " + invokeType); } } @Override final public int getPoppedCount() { return (getInvocationCode().equals(Dispatch.STATIC) ? 0 : 1) + Util.getParamsCount(getMethodSignature()); } @Override final public String getPushedType(String[] types) { String t = Util.getReturnType(getMethodSignature()); if (t.equals(Constants.TYPE_void)) { return null; } else { return t; } } @Override final public byte getPushedWordSize() { String t = getMethodSignature(); int index = t.lastIndexOf(')'); return Util.getWordSize(t, index + 1); } public BootstrapMethod getBootstrap() { return bootstrap; } @Override public String getMethodSignature() { return methodType; } @Override public String getMethodName() { return methodName; } @Override public String getClassType() { return getBootstrap().methodClass(); } @Override public void visit(Visitor v) { v.visitInvoke(this); } @Override public String toString() { return "InvokeDynamic [" + getBootstrap() + "] " + getMethodName() + getMethodSignature(); } final static class Lazy extends InvokeDynamicInstruction { final private ConstantPoolReader cp; final private int index; Lazy(short opcode, ConstantPoolReader cp, int index) { super(opcode, null, null, null); this.index = index; this.cp = cp; } int getCPIndex() { return index; } @Override public BootstrapMethod getBootstrap() { if (bootstrap == null) { bootstrap = cp.getConstantPoolDynamicBootstrap(index); } return bootstrap; } @Override public String getMethodName() { if (methodName == null) { methodName = cp.getConstantPoolDynamicName(index); } return methodName; } @Override public String getMethodSignature() { if (methodType == null) { methodType = cp.getConstantPoolDynamicType(index); } return methodType; } @Override ConstantPoolReader getLazyConstantPool() { return cp; } } public CallSite bootstrap(Class cl) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException { ClassLoader bootstrapCL = cl.getClassLoader(); Class<?> bootstrapClass = Class.forName(getBootstrap().methodClass().replace('/', '.'), false, bootstrapCL); MethodType bt = MethodType.fromMethodDescriptorString(bootstrap.methodType(), bootstrapCL); Method bootstrap = bootstrapClass.getMethod(this.bootstrap.methodName(), bt.parameterList().toArray(new Class[ bt.parameterCount() ])); Object[] args = new Object[ bt.parameterCount() ]; Lookup myLookup = MethodHandles.lookup().in(cl); Field impl_lookup = Lookup.class.getDeclaredField("IMPL_LOOKUP"); // get the required field via reflections impl_lookup.setAccessible(true); // set it accessible Lookup lutrusted = (Lookup) impl_lookup.get(myLookup); // get the value of IMPL_LOOKUP from the Lookup instance and save it in a new Lookup object args[0] = lutrusted; args[1] = getMethodName(); args[2] = MethodType.fromMethodDescriptorString(getMethodSignature(), cl.getClassLoader()); for(int i = 3; i < bt.parameterCount(); i++) { args[i] = getBootstrap().callArgument(bootstrapCL,i-3); } //bootstrap.setAccessible(true); return (CallSite) bootstrap.invoke(null, args); } static InvokeDynamicInstruction make(ConstantPoolReader cp, int index, int mode) { if (mode != OP_invokedynamic) { throw new IllegalArgumentException("Unknown mode: " + mode); } return new Lazy((short) mode, cp, index); } }