/****************************************************************************** * 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 *****************************************************************************/ /* * Copyright (c) 2013, * Tobias Blaschke <code@tobiasblaschke.de> * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The names of the contributors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package com.ibm.wala.util.ssa; import java.util.Collection; import java.util.Collections; import java.util.List; import com.ibm.wala.classLoader.CallSiteReference; import com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory; import com.ibm.wala.classLoader.NewSiteReference; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.shrikeBT.IConditionalBranchInstruction; import com.ibm.wala.shrikeBT.IInvokeInstruction; import com.ibm.wala.ssa.SSAArrayLoadInstruction; import com.ibm.wala.ssa.SSAArrayStoreInstruction; import com.ibm.wala.ssa.SSAConditionalBranchInstruction; import com.ibm.wala.ssa.SSAGetInstruction; import com.ibm.wala.ssa.SSAGotoInstruction; import com.ibm.wala.ssa.SSAInvokeInstruction; import com.ibm.wala.ssa.SSANewInstruction; import com.ibm.wala.ssa.SSAPhiInstruction; import com.ibm.wala.ssa.SSAPutInstruction; import com.ibm.wala.ssa.SSAReturnInstruction; import com.ibm.wala.types.FieldReference; import com.ibm.wala.types.MethodReference; import com.ibm.wala.types.TypeReference; /** * Intended for SyntheticMethods, uses JavaInstructionFactory. * * As the name states this SSAInstructionFactory does type checks. If they pass the actual instructions are * generated using the JavaInstructionFactory. * * Obviously this factory is not complete yet. It's extended on demand. * * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory * * @author Tobias Blaschke <code@tobiasblaschke.de> * @since 2013-10-20 */ public class TypeSafeInstructionFactory { private final static boolean DEBUG = false; protected final JavaInstructionFactory insts; protected final IClassHierarchy cha; public TypeSafeInstructionFactory(IClassHierarchy cha) { this.cha = cha; this.insts = new JavaInstructionFactory(); } /** * result = site(params). * * Instruction that calls a method which has a return-value. * * All parameters (but exception) are typechecked first. If the check passes they get unpacked and handed over * to the corresponding JavaInstructionFactory.InvokeInstruction. * * Calls result.setAssigned() * * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.InvokeInstruction(int, int, int[], int, CallSiteReference) * * @param iindex Zero or a positive number unique to any instruction of the same method * @param result Where to place the return-value of the called method. Is SSAValue.setAssigned() automatically. * @param params Parameters to the call starting with the implicit this-pointer if necessary * @param exception An SSAValue receiving the exception-object when something in the method throws unhandled * @param site The CallSiteReference to this call. */ public SSAInvokeInstruction InvokeInstruction(final int iindex, final SSAValue result, List<? extends SSAValue> params, final SSAValue exception, final CallSiteReference site) { info("Now: InvokeInstruction to {} using {}", site, params); if (iindex < 0) { throw new IllegalArgumentException("The iIndex may not be negative"); } if (result == null) { throw new IllegalArgumentException("The result may not be null"); } if (exception == null) { throw new IllegalArgumentException("The parameter exception may not be null"); } if (params == null) { params = Collections.EMPTY_LIST; } if (site == null) { throw new IllegalArgumentException("The CallSite may not be null"); } final ParameterAccessor acc = new ParameterAccessor(site.getDeclaredTarget(), this.cha); if (acc.hasImplicitThis()) { if (params.size() != (acc.getNumberOfParameters() + 1)) { throw new IllegalArgumentException("The callee takes " + acc.getNumberOfParameters() + " + 1 (implicit this) " + "parameters. The given parameter-list has length " + params.size() + ". They are: " + params); } if (site.getInvocationCode() == IInvokeInstruction.Dispatch.STATIC) { // TODO use Dispatch.hasImplicitThis throw new IllegalArgumentException("A function expecting an implicit this can not be invoked static."); } } else { if (params.size() != (acc.getNumberOfParameters())) { throw new IllegalArgumentException("The callee takes " + acc.getNumberOfParameters() + " parameters (no implicit this)." + "The given parameter-list has length " + params.size() + ". They are: " + params); } if (site.getInvocationCode() != IInvokeInstruction.Dispatch.STATIC) { throw new IllegalArgumentException("A function without implicit this can only be invoked static."); } } final MethodReference mRef = site.getDeclaredTarget(); // *********** // Params cosher, start typechecks { // Return-Value final TypeReference retType = acc.getReturnType(); if (! isAssignableFrom(retType, result.getType())) { throw new IllegalArgumentException("The return-value does not stand the TypeCheck! " + retType + " is not assignable to " + result); } } final int[] aParams = new int[params.size()]; if (acc.hasImplicitThis()) { // Implicit This final SSAValue targetThis = acc.getThis(); final SSAValue givenThis = params.get(0); aParams[0] = givenThis.getNumber(); if (! isAssignableFrom(givenThis.getType(), targetThis.getType())) { throw new IllegalArgumentException("Parameter 'this' is not assignable from\n\t" + givenThis + " to\n\t" + targetThis + "\n----------"); } for (int i = 1; i < params.size(); ++i) { // "regular" parameters final SSAValue givenParam = params.get(i); final SSAValue targetParam = acc.getParameter(i); aParams[i] = givenParam.getNumber(); if (! isAssignableFrom(givenParam.getType(), targetParam.getType())) { throw new IllegalArgumentException("Parameter " + i + " is not assignable from " + givenParam + " to " + targetParam); } if (result.equals(givenParam)) { throw new IllegalArgumentException(result.toString() + " can't be the result and parameter " + i + " at the same time in " + site); } } } else { for (int i = 0; i < params.size(); ++i) { // "regular" parameters final SSAValue givenParam = params.get(i); final SSAValue targetParam = acc.getParameter(i + 1); aParams[i] = givenParam.getNumber(); if (! isAssignableFrom(givenParam.getType(), targetParam.getType())) { throw new IllegalArgumentException("Parameter " + (i + 1) + " is not assignable from " + givenParam + " to " + targetParam + " in call " + site); } if (result.equals(givenParam)) { throw new IllegalArgumentException(result.toString() + " can't be the result and parameter " + i + " at the same time in " + site); } } } // TODO somehow check exception? result.setAssigned(); return insts.InvokeInstruction(iindex, result.getNumber(), aParams, exception.getNumber(), site); } /** * Instruction that calls a void-method. * * All parameters (but exception) are typechecked first. If the check passes they get unpacked and handed over * to the corresponding JavaInstructionFactory.InvokeInstruction. * * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.InvokeInstruction(int, int[], int, CallSiteReference) * * @param iindex Zero or a positive number unique to any instruction of the same method * @param params Parameters to the call starting with the implicit this-pointer if necessary * @param exception An SSAValue receiving the exception-object when something in the method throws unhandled * @param site The CallSiteReference to this call. */ public SSAInvokeInstruction InvokeInstruction(final int iindex, List<? extends SSAValue> params, final SSAValue exception, final CallSiteReference site) { info("Now: InvokeInstruction to {} using {}", site, params); if (iindex < 0) { throw new IllegalArgumentException("The iIndex may not be negative"); } if (exception == null) { throw new IllegalArgumentException("The parameter exception may not be null"); } if (params == null) { params = Collections.EMPTY_LIST; } if (site == null) { throw new IllegalArgumentException("The CallSite may not be null"); } final ParameterAccessor acc = new ParameterAccessor(site.getDeclaredTarget(), this.cha); if (acc.hasImplicitThis()) { if (params.size() != (acc.getNumberOfParameters() + 1)) { throw new IllegalArgumentException("The callee takes " + acc.getNumberOfParameters() + " + 1 (implicit this) " + "parameters. The given parameter-list has length " + params.size() + ". They are: " + params); } if (site.getInvocationCode() == IInvokeInstruction.Dispatch.STATIC) { // TODO use Dispatch.hasImplicitThis throw new IllegalArgumentException("A function expecting an implicit this can not be invoked static."); } } else { if (params.size() != (acc.getNumberOfParameters())) { throw new IllegalArgumentException("The callee takes " + acc.getNumberOfParameters() + " parameters (no implicit this)." + "The given parameter-list has length " + params.size() + ". They are: " + params); } if (site.getInvocationCode() != IInvokeInstruction.Dispatch.STATIC) { throw new IllegalArgumentException("A function without implicit this can only be invoked static."); } } final MethodReference mRef = site.getDeclaredTarget(); // *********** // Params cosher, start typechecks { // Return-Value if (acc.hasReturn()) { throw new IllegalArgumentException("This InvokeInstruction only works on void-functions but " + mRef + " returns a value."); } } final int[] aParams = new int[params.size()]; if (acc.hasImplicitThis()) { // Implicit This final SSAValue targetThis = acc.getThis(); final SSAValue givenThis = params.get(0); aParams[0] = givenThis.getNumber(); /*if (! isAssignableFrom(givenThis.getType(), targetThis.getType())) { throw new IllegalArgumentException("Parameter 'this' is not assignable from " + givenThis + " to " + targetThis); }*/ for (int i = 1; i < params.size(); ++i) { // "regular" parameters final SSAValue givenParam = params.get(i); final SSAValue targetParam = acc.getParameter(i); aParams[i] = givenParam.getNumber(); if (! isAssignableFrom(givenParam.getType(), targetParam.getType())) { throw new IllegalArgumentException("Parameter " + i + " is not assignable from\n\t" + givenParam + " to\n\t" + targetParam + "\nin call " + site + "\n---------"); } } } else { for (int i = 0; i < params.size(); ++i) { // "regular" parameters final SSAValue givenParam = params.get(i); final SSAValue targetParam = acc.getParameter(i + 1); aParams[i] = givenParam.getNumber(); if (! isAssignableFrom(givenParam.getType(), targetParam.getType())) { throw new IllegalArgumentException("Parameter " + (i + 1) + " is not assignable from " + givenParam + " to " + targetParam); } } } // TODO somehow check exception? return insts.InvokeInstruction(iindex, aParams, exception.getNumber(), site); } /** * Check if the type of the SSAValue is assignable to the return-value of the method it's valid in. * * If type check passes the corresponding ReturnInstruction of the JavaInstructionFactory is called. * * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.ReturnInstruction(int, int, boolean) * * @param iindex Zero or a positive number unique to any instruction of the same method * @param result SSAValue to return _with_ validIn _set_! * @throws IllegalArgumentException if result has no validIn set */ public SSAReturnInstruction ReturnInstruction(final int iindex, final SSAValue result) { info("Now: ReturnInstruction using {}", result); if (iindex < 0) { throw new IllegalArgumentException("iIndex may not be negative"); } if (! isAssignableFrom(result.getType(), result.getValidIn().getReturnType())) { throw new IllegalArgumentException("Return type not assignable from " + result.getType() + " to " + result.getValidIn().getReturnType()); } return insts.ReturnInstruction(iindex, result.getNumber(), result.getType().isPrimitiveType()); } /** * targetValue = containingInstance.field. * * Reads field from containingInstance into targetValue. * If type check passes the corresponding GetInstruction of the JavaInstructionFactory is called. * Calls targetValue.setAssigned() * * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.GetInstruction(int, int, int, FieldReference) * * @param iindex Zero or a positive number unique to any instruction of the same method * @param targetValue the result of the GetInstruction is placed there * @param containingInstance The Object instance to read the field from * @param field The description of the field */ public SSAGetInstruction GetInstruction(final int iindex, final SSAValue targetValue, final SSAValue containingInstance, FieldReference field) { info("Now: Get {} from {} into {}", field, containingInstance, targetValue); if (iindex < 0) { throw new IllegalArgumentException("iIndex may not be negative"); } if (targetValue == null) { throw new IllegalArgumentException("targetValue may not be null"); } if (containingInstance == null) { throw new IllegalArgumentException("containingInstance may not be null"); } if (field == null) { throw new IllegalArgumentException("field may not be null"); } if (! isSuperclassOf(field.getDeclaringClass(), containingInstance.getType())) { throw new IllegalArgumentException("The targetInstance " + containingInstance + " is not equal or a " + " super-class of " + field.getDeclaringClass()); } if (! isAssignableFrom(field.getFieldType(), targetValue.getType())) { throw new IllegalArgumentException("The field " + targetValue + " is not assignable from " + field); } final MethodReference targetValueValidIn = targetValue.getValidIn(); final MethodReference instValidIn = containingInstance.getValidIn(); if ((targetValueValidIn != null) && (instValidIn != null) && (! targetValueValidIn.equals(instValidIn))) { throw new IllegalArgumentException("containingInstance " + containingInstance + "and targetValue " + targetValue + " are valid in different scopes"); } targetValue.setAssigned(); return insts.GetInstruction(iindex, targetValue.getNumber(), containingInstance.getNumber(), field); } /** * Reads static field into targetValue. * * If type check passes the corresponding GetInstruction of the JavaInstructionFactory is called. * Calls targetValue.setAssigned() * * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.GetInstruction(int, int, int, FieldReference) * * @param iindex Zero or a positive number unique to any instruction of the same method * @param targetValue the result of the GetInstruction is placed there * @param containingInstance The Object instance to read the field from * @param field The description of the field */ public SSAGetInstruction GetInstruction(final int iindex, final SSAValue targetValue, FieldReference field) { info("Now: Get {} into {}", field, targetValue); if (iindex < 0) { throw new IllegalArgumentException("iIndex may not be negative"); } if (targetValue == null) { throw new IllegalArgumentException("targetValue may not be null"); } if (field == null) { throw new IllegalArgumentException("field may not be null"); } if (! isAssignableFrom(field.getFieldType(), targetValue.getType())) { throw new IllegalArgumentException("The field " + targetValue + " is not assignable from " + field); } targetValue.setAssigned(); return insts.GetInstruction(iindex, targetValue.getNumber(), field); } /** * Writes newValue to field of targetInstance. * * If type check passes the corresponding PutInstruction of the JavaInstructionFactory is called. * * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.PutInstruction(int, int, int, FieldReference) * * @param iindex Zero or a psitive number unique to any instruction of the same method * @param targetInstance the instance of the object to write a field of * @param newValue The value to write to the field * @param field The description of the target */ public SSAPutInstruction PutInstruction(final int iindex, final SSAValue targetInstance, final SSAValue newValue, FieldReference field) { info("Now: Put {} to {}", newValue, field); if (iindex < 0) { throw new IllegalArgumentException("iIndex may not be negative"); } if (targetInstance == null) { throw new IllegalArgumentException("targetInstance may not be null"); } if (newValue == null) { throw new IllegalArgumentException("newValue may not be null"); } if (field == null) { throw new IllegalArgumentException("field may not be null"); } if (! isSuperclassOf(field.getDeclaringClass(), targetInstance.getType())) { throw new IllegalArgumentException("The targetInstance " + targetInstance + " is not equal or a " + " super-class of " + field.getDeclaringClass()); } if (! isAssignableFrom(newValue.getType(), field.getFieldType())) { throw new IllegalArgumentException("The field " + field + " is not assignable from " + newValue); } final MethodReference newValueValidIn = newValue.getValidIn(); final MethodReference instValidIn = targetInstance.getValidIn(); if ((newValueValidIn != null) && (instValidIn != null) && (! newValueValidIn.equals(instValidIn))) { throw new IllegalArgumentException("targetInstance " + targetInstance + "and newValue " + newValue + " are valid in different scopes"); } return insts.PutInstruction(iindex, targetInstance.getNumber(), newValue.getNumber(), field); } /** * Writes newValue to static field. * * If type check passes the corresponding PutInstruction of the JavaInstructionFactory is called. * * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.PutInstruction(int, int, int, FieldReference) * * @param iindex Zero or a psitive number unique to any instruction of the same method * @param targetInstance the instance of the object to write a field of * @param newValue The value to write to the field * @param field The description of the target */ public SSAPutInstruction PutInstruction(final int iindex, final SSAValue newValue, FieldReference field) { info("Now: Put {} to {}", newValue, field); if (iindex < 0) { throw new IllegalArgumentException("iIndex may not be negative"); } if (newValue == null) { throw new IllegalArgumentException("newValue may not be null"); } if (field == null) { throw new IllegalArgumentException("field may not be null"); } if (! isAssignableFrom(newValue.getType(), field.getFieldType())) { throw new IllegalArgumentException("The field " + field + " is not assignable from " + newValue); } final MethodReference newValueValidIn = newValue.getValidIn(); return insts.PutInstruction(iindex, newValue.getNumber(), field); } public SSANewInstruction NewInstruction(int iindex, SSAValue result, NewSiteReference site) { info("Now: New {}", result); if (iindex < 0) { throw new IllegalArgumentException("iIndex may not be negative"); } if (result == null) { throw new IllegalArgumentException("result may not be null"); } if (site == null) { throw new IllegalArgumentException("site may not be null"); } if (! isAssignableFrom(site.getDeclaredType(), result.getType())) { throw new IllegalArgumentException("type mismatch"); } result.setAssigned(); return insts.NewInstruction(iindex, result.getNumber(), site); } public SSANewInstruction NewInstruction(int iindex, SSAValue result, NewSiteReference site, Collection<? extends SSAValue> params) { info("Now: New {}", result); if (iindex < 0) { throw new IllegalArgumentException("iIndex may not be negative"); } if (result == null) { throw new IllegalArgumentException("result may not be null"); } if (site == null) { throw new IllegalArgumentException("site may not be null"); } if (! isAssignableFrom(site.getDeclaredType(), result.getType())) { throw new IllegalArgumentException("type mismatch"); } final MethodReference resultValidIn = result.getValidIn(); final int[] aParams = new int[params.size()]; int i = 0; for (final SSAValue param : params) { final MethodReference paramValidIn = param.getValidIn(); if ((resultValidIn != null) && (paramValidIn != null) && (! paramValidIn.equals(resultValidIn))) { throw new IllegalArgumentException("The parameter " + param + " is valid in another scope than" + result); } aParams[i] = param.getNumber(); i++; } result.setAssigned(); return insts.NewInstruction(iindex, result.getNumber(), site, aParams); } /** * Combine SSA-Values into a newone. * * If type check passes the corresponding PhiInstruction of the JavaInstructionFactory is called. * Calls result.setAssigned(). * * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.PhiInstruction(int, int, int[]) * * @param iindex Zero or a positive number unique to any instruction of the same method * @param result Where to write result to * @param params at least one SSAValue to read from */ public SSAPhiInstruction PhiInstruction(int iindex, SSAValue result, Collection<? extends SSAValue> params) { info("Now: Phi into {} from {}", result, params); if (iindex < 0) { throw new IllegalArgumentException("iIndex may not be negative"); } if (result == null) { throw new IllegalArgumentException("result may not be null"); } if (params == null) { throw new IllegalArgumentException("params may not be null"); } if (params.size() < 1) { throw new IllegalArgumentException("Phi needs at least one source value. Type is " + result.getType()); } final MethodReference resultValidIn = result.getValidIn(); final TypeReference resultType = result.getType(); final int[] aParams = new int[params.size()]; int i = 0; for (final SSAValue param : params) { final MethodReference paramValidIn = param.getValidIn(); if ((resultValidIn != null) && (paramValidIn != null) && (! paramValidIn.equals(resultValidIn))) { throw new IllegalArgumentException("The parameter " + param + " is valid in another scope than" + result); } if (! isAssignableFrom(param.getType(), resultType)) { throw new IllegalArgumentException("Param " + param + " is not assignable to " + result); } if (result.equals(param)) { throw new IllegalArgumentException("Cannot phi to myself: " + result); } aParams[i] = param.getNumber(); i++; // TODO: Assert no parameter appears twice } result.setAssigned(); return insts.PhiInstruction(iindex, result.getNumber(), aParams); } private boolean isSuperclassOf(final TypeReference superClass, final TypeReference subClass) { return true; // TODO } public boolean isAssignableFrom(final TypeReference from, final TypeReference to) { try { return ParameterAccessor.isAssignable(from, to, this.cha); } catch (ClassLookupException e) { return true; } } // ************ // Instructions simply handed through follow /** * Return from a void-function. * * Handed through to JavaInstructionFactory directly (unless the iindex is negative). * * @param iindex Zero or a positive number unique to any instruction of the same method */ public SSAReturnInstruction ReturnInstruction(final int iindex) { if (iindex < 0) { throw new IllegalArgumentException("The iindex may not be negative"); } return insts.ReturnInstruction(iindex); } /** * Unconditionally jump to a (non-Phi) Instruction. * * @param target the iindex of the instruction to jump to */ public SSAGotoInstruction GotoInstruction(final int iindex, final int target) { if (iindex < 0) { throw new IllegalArgumentException("The iindex may not be negative"); } if (target < 0) { throw new IllegalArgumentException("The target-iindex may not be negative"); } return insts.GotoInstruction(iindex, target); } public SSAConditionalBranchInstruction ConditionalBranchInstruction(final int iindex, final IConditionalBranchInstruction.IOperator operator, final TypeReference type, final int val1, final int val2, final int target) { return insts.ConditionalBranchInstruction(iindex, operator, type, val1, val2, target); } /** * result = array[index]. * * Load a a reference from an array. * * @param result The SSAValue to store the loaded stuff in * @param array The array to load from * @param index Te position in array to load from */ public SSAArrayLoadInstruction ArrayLoadInstruction(final int iindex, final SSAValue result, final SSAValue array, final int index) { if (iindex < 0) { throw new IllegalArgumentException("The iindex may not be negative. It's " + iindex); } if (result == null) { throw new IllegalArgumentException("Can't use null for the result"); } if (array == null) { throw new IllegalArgumentException("Can't load from array null"); } if (index < 0) { throw new IllegalArgumentException("The index in the array may not be negative. It's " + index); } if (! array.getType().isArrayType()) { throw new IllegalArgumentException("The array to read from is expected to be ... well ... an array. The given value was " + array ); } final TypeReference innerType = array.getType().getArrayElementType(); if (! isAssignableFrom(innerType, result.getType())) { throw new IllegalArgumentException("Can't assign from an array of " + innerType.getName() + " to " + result.getType().getName()); } result.setAssigned(); return insts.ArrayLoadInstruction(iindex, result.getNumber(), array.getNumber(), index, innerType); } /** * array[index] = value. * * Save a value to a specific position in an Array. * * @param array the array to store to * @param index the position in the array to place value at * @param value The SSAValue to store in the array */ public SSAArrayStoreInstruction ArrayStoreInstruction(final int iindex, final SSAValue array, final int index, final SSAValue value) { if (iindex < 0) { throw new IllegalArgumentException("The iindex may not be negative. It's " + iindex); } if (value == null) { throw new IllegalArgumentException("Can't use null for the value to put"); } if (array == null) { throw new IllegalArgumentException("Can't write to array null"); } if (index < 0) { throw new IllegalArgumentException("The index in the array may not be negative. It's " + index); } if (! array.getType().isArrayType()) { throw new IllegalArgumentException("The array to write to is expected to be ... well ... an array. The given value was " + array ); } final TypeReference innerType = array.getType().getArrayElementType(); if (! isAssignableFrom(value.getType(), innerType)) { throw new IllegalArgumentException("Can't assign to an array of " + innerType.getName() + " from " + value.getType().getName()); } return insts.ArrayStoreInstruction(iindex, array.getNumber(), index, value.getNumber(), innerType); } private static void info(String s, Object ... args) { if (DEBUG) { System.err.printf(s, args); } } }