package nl.tudelft.simulation.dsol.interpreter.operations.reflection; import java.io.DataInput; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import org.djutils.primitives.Primitive; import org.djutils.reflection.ClassUtil; import org.djutils.reflection.MethodSignature; import nl.tudelft.simulation.dsol.interpreter.Frame; import nl.tudelft.simulation.dsol.interpreter.Interpreter; import nl.tudelft.simulation.dsol.interpreter.InterpreterException; import nl.tudelft.simulation.dsol.interpreter.LocalVariable; import nl.tudelft.simulation.dsol.interpreter.classfile.ConstantMethodref; import nl.tudelft.simulation.dsol.interpreter.operations.InvokeOperation; import nl.tudelft.simulation.dsol.interpreter.operations.NEW; /** * INVOKESPECIAL. *

* Copyright (c) 2002-2022 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See * for project information https://simulation.tudelft.nl. The DSOL * project is distributed under a three-clause BSD-style license, which can be found at * * https://simulation.tudelft.nl/dsol/3.0/license.html. *

* @author Peter Jacobs * @author Alexander Verbraeck */ public class INVOKESPECIAL extends InvokeOperation { /** OP refers to the operand code. */ public static final int OP = 183; /** the index to load. */ private final int index; /** * constructs a new INVOKESPECIAL. * @param dataInput DataInput; the dataInput * @throws IOException on IOfailure */ public INVOKESPECIAL(final DataInput dataInput) throws IOException { super(); this.index = dataInput.readUnsignedShort(); } /** {@inheritDoc} */ @Override public Frame execute(final Frame frame) { try { ConstantMethodref constantMethodref = (ConstantMethodref) frame.getConstantPool()[this.index]; Class[] parameterTypes = new MethodSignature(constantMethodref.getConstantNameAndType().getDescriptor()).getParameterTypes(); String methodName = constantMethodref.getConstantNameAndType().getName(); if (methodName.equals("")) { Object[] args = new Object[parameterTypes.length]; for (int i = args.length - 1; i > -1; i--) { args[i] = Primitive.cast(parameterTypes[i], frame.getOperandStack().pop()); } Object objectRef = frame.getOperandStack().pop(); Class instanceClass = ((NEW.UninitializedInstance) objectRef).getInstanceClass(); Constructor constructor = ClassUtil.resolveConstructor(instanceClass, parameterTypes); constructor.setAccessible(true); Object result = constructor.newInstance(args); frame.getOperandStack().replace(objectRef, result); LocalVariable.replace(frame.getLocalVariables(), objectRef, result); if (Interpreter.DEBUG) { System.out.println(" " + instanceClass.getSimpleName() + "."); } return null; } Object objectRef = frame.getOperandStack().peek(parameterTypes.length); // Now the normal methods Method method = null; // look if we need to resolve a super() method Class referenceClass = constantMethodref.getConstantClass().getValue().getClassValue(); if (objectRef.getClass().getSuperclass().equals(referenceClass)) { method = ClassUtil.resolveMethod(objectRef.getClass().getSuperclass(), methodName, parameterTypes); } else { method = ClassUtil.resolveMethod(objectRef, methodName, parameterTypes); } synchronized (frame.getOperandStack()) { // Let's create the arguments Object[] args = new Object[parameterTypes.length]; for (int i = args.length - 1; i > -1; i--) { args[i] = Primitive.cast(parameterTypes[i], frame.getOperandStack().pop()); } frame.getOperandStack().pop(); return this.execute(frame, objectRef, method, args); } } catch (Exception exception) { throw new InterpreterException(exception); } } /** * executes the method on the objectRef. * @param frame Frame; the frame * @param objectRef Object; the objectRef * @param method Method; the method * @param arguments Object[]; the arguments * @return the resulting Frame * @throws Exception on reflection exception */ public Frame execute(final Frame frame, final Object objectRef, final Method method, final Object[] arguments) throws Exception { if (Interpreter.DEBUG) { System.out.println(" invoke " + objectRef.getClass().getSimpleName() + "." + method.getName()); } method.setAccessible(true); Object result = null; try { result = method.invoke(objectRef, arguments); } catch (Exception exception) { frame.getOperandStack().push(exception.getCause()); throw exception; } // Let's see what to do with the stack if (!method.getReturnType().equals(void.class)) { frame.getOperandStack().push(result); } return null; } /** {@inheritDoc} */ @Override public int getByteLength() { return OPCODE_BYTE_LENGTH + 2; } /** {@inheritDoc} */ @Override public int getOpcode() { return INVOKESPECIAL.OP; } }