diff --git a/src/main/java/com/aparapi/Kernel.java b/src/main/java/com/aparapi/Kernel.java index ecdff9200928312452fed79a76b28bc3a5ede98e..0692c1d77b1c43b54e20cc1960a919cd9a58e063 100644 --- a/src/main/java/com/aparapi/Kernel.java +++ b/src/main/java/com/aparapi/Kernel.java @@ -1,3027 +1,3027 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi; - -import com.aparapi.annotation.Experimental; -import com.aparapi.exception.DeprecatedException; -import com.aparapi.internal.model.CacheEnabler; -import com.aparapi.internal.model.ClassModel.ConstantPool.MethodReferenceEntry; -import com.aparapi.internal.model.ClassModel.ConstantPool.NameAndTypeEntry; -import com.aparapi.internal.model.ValueCache; -import com.aparapi.internal.model.ValueCache.ThrowingValueComputer; -import com.aparapi.internal.model.ValueCache.ValueComputer; -import com.aparapi.internal.opencl.OpenCLLoader; - -import java.lang.annotation.Annotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.reflect.Method; -import java.util.ArrayDeque; -import java.util.Arrays; -import java.util.Collections; -import java.util.Deque; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CyclicBarrier; -import java.util.logging.Logger; - -import com.aparapi.device.Device; -import com.aparapi.device.JavaDevice; -import com.aparapi.device.OpenCLDevice; -import com.aparapi.internal.kernel.KernelArg; -import com.aparapi.internal.kernel.KernelManager; -import com.aparapi.internal.kernel.KernelProfile; -import com.aparapi.internal.kernel.KernelRunner; -import com.aparapi.internal.util.Reflection; -import com.aparapi.internal.util.UnsafeWrapper; - -/** - * A <i>kernel</i> encapsulates a data parallel algorithm that will execute either on a GPU - * (through conversion to OpenCL) or on a CPU via a Java Thread Pool. - * <p> - * To write a new kernel, a developer extends the <code>Kernel</code> class and overrides the <code>Kernel.run()</code> method. - * To execute this kernel, the developer creates a new instance of it and calls <code>Kernel.execute(int globalSize)</code> with a suitable 'global size'. At runtime - * Aparapi will attempt to convert the <code>Kernel.run()</code> method (and any method called directly or indirectly - * by <code>Kernel.run()</code>) into OpenCL for execution on GPU devices made available via the OpenCL platform. - * <p> - * Note that <code>Kernel.run()</code> is not called directly. Instead, - * the <code>Kernel.execute(int globalSize)</code> method will cause the overridden <code>Kernel.run()</code> - * method to be invoked once for each value in the range <code>0...globalSize</code>. - * <p> - * On the first call to <code>Kernel.execute(int _globalSize)</code>, Aparapi will determine the EXECUTION_MODE of the kernel. - * This decision is made dynamically based on two factors: - * <ol> - * <li>Whether OpenCL is available (appropriate drivers are installed and the OpenCL and Aparapi dynamic libraries are included on the system path).</li> - * <li>Whether the bytecode of the <code>run()</code> method (and every method that can be called directly or indirectly from the <code>run()</code> method) - * can be converted into OpenCL.</li> - * </ol> - * <p> - * Below is an example Kernel that calculates the square of a set of input values. - * <p> - * <blockquote><pre> - * class SquareKernel extends Kernel{ - * private int values[]; - * private int squares[]; - * public SquareKernel(int values[]){ - * this.values = values; - * squares = new int[values.length]; - * } - * public void run() { - * int gid = getGlobalID(); - * squares[gid] = values[gid]*values[gid]; - * } - * public int[] getSquares(){ - * return(squares); - * } - * } - * </pre></blockquote> - * <p> - * To execute this kernel, first create a new instance of it and then call <code>execute(Range _range)</code>. - * <p> - * <blockquote><pre> - * int[] values = new int[1024]; - * // fill values array - * Range range = Range.create(values.length); // create a range 0..1024 - * SquareKernel kernel = new SquareKernel(values); - * kernel.execute(range); - * </pre></blockquote> - * <p> - * When <code>execute(Range)</code> returns, all the executions of <code>Kernel.run()</code> have completed and the results are available in the <code>squares</code> array. - * <p> - * <blockquote><pre> - * int[] squares = kernel.getSquares(); - * for (int i=0; i< values.length; i++){ - * System.out.printf("%4d %4d %8d\n", i, values[i], squares[i]); - * } - * </pre></blockquote> - * <p> - * A different approach to creating kernels that avoids extending Kernel is to write an anonymous inner class: - * <p> - * <blockquote><pre> - * - * final int[] values = new int[1024]; - * // fill the values array - * final int[] squares = new int[values.length]; - * final Range range = Range.create(values.length); - * - * Kernel kernel = new Kernel(){ - * public void run() { - * int gid = getGlobalID(); - * squares[gid] = values[gid]*values[gid]; - * } - * }; - * kernel.execute(range); - * for (int i=0; i< values.length; i++){ - * System.out.printf("%4d %4d %8d\n", i, values[i], squares[i]); - * } - * - * </pre></blockquote> - * <p> - * - * @author gfrost AMD Javalabs - * @version Alpha, 21/09/2010 - */ -public abstract class Kernel implements Cloneable { - - private static Logger logger = Logger.getLogger(Config.getLoggerName()); - - /** - * We can use this Annotation to 'tag' intended local buffers. - * - * So we can either annotate the buffer - * <pre><code> - * @Local int[] buffer = new int[1024]; - * </code></pre> - * Or use a special suffix - * <pre><code> - * int[] buffer_$local$ = new int[1024]; - * </code></pre> - * - * @see #LOCAL_SUFFIX - * - * - */ - @Retention(RetentionPolicy.RUNTIME) - public @interface Local { - - } - - /** - * We can use this Annotation to 'tag' intended constant buffers. - * - * So we can either annotate the buffer - * <pre><code> - * @Constant int[] buffer = new int[1024]; - * </code></pre> - * Or use a special suffix - * <pre><code> - * int[] buffer_$constant$ = new int[1024]; - * </code></pre> - * - * @see #LOCAL_SUFFIX - * - * - */ - @Retention(RetentionPolicy.RUNTIME) - public @interface Constant { - - } - - /** - * - * We can use this Annotation to 'tag' __private (unshared) array fields. Data in the __private address space in OpenCL is accessible only from - * the current kernel instance. - * - * To so mark a field with a buffer size of 99, we can either annotate the buffer - * <pre><code> - * @PrivateMemorySpace(99) int[] buffer = new int[99]; - * </code></pre> - * Or use a special suffix - * <pre><code> - * int[] buffer_$private$99 = new int[99]; - * </code></pre> - * - * <p>Note that any code which must be runnable in {@link EXECUTION_MODE#JTP} will fail to work correctly if it uses such an - * array, as the array will be shared by all threads. The solution is to create a {@link NoCL} method called at the start of {@link #run()} which sets - * the field to an array returned from a static <code>ThreadLocal<foo[]></code></p>. Please see <code>MedianKernel7x7</code> in the samples for an example. - * - * @see #PRIVATE_SUFFIX - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.FIELD}) - public @interface PrivateMemorySpace { - /** Size of the array used as __private buffer. */ - int value(); - } - - /** - * Annotation which can be applied to either a getter (with usual java bean naming convention relative to an instance field), or to any method - * with void return type, which prevents both the method body and any calls to the method being emitted in the generated OpenCL. (In the case of a getter, the - * underlying field is used in place of the NoCL getter method.) This allows for code specialization within a java/JTP execution path, for example to - * allow logging/breakpointing when debugging, or to apply ThreadLocal processing (see {@link PrivateMemorySpace}) in java to simulate OpenCL __private - * memory. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD, ElementType.FIELD}) - public @interface NoCL { - // empty - } - - /** - * We can use this suffix to 'tag' intended local buffers. - * - * - * So either name the buffer - * <pre><code> - * int[] buffer_$local$ = new int[1024]; - * </code></pre> - * Or use the Annotation form - * <pre><code> - * @Local int[] buffer = new int[1024]; - * </code></pre> - */ - public final static String LOCAL_SUFFIX = "_$local$"; - - /** - * We can use this suffix to 'tag' intended constant buffers. - * - * - * So either name the buffer - * <pre><code> - * int[] buffer_$constant$ = new int[1024]; - * </code></pre> - * Or use the Annotation form - * <pre><code> - * @Constant int[] buffer = new int[1024]; - * </code></pre> - */ - public final static String CONSTANT_SUFFIX = "_$constant$"; - - /** - * We can use this suffix to 'tag' __private buffers. - * - * <p>So either name the buffer - * <pre><code> - * int[] buffer_$private$32 = new int[32]; - * </code></pre> - * Or use the Annotation form - * <pre><code> - * @PrivateMemorySpace(32) int[] buffer = new int[32]; - * </code></pre> - * - * @see PrivateMemorySpace for a more detailed usage summary - */ - public final static String PRIVATE_SUFFIX = "_$private$"; - - /** - * This annotation is for internal use only - */ - @Retention(RetentionPolicy.RUNTIME) - protected @interface OpenCLDelegate { - - } - - /** - * This annotation is for internal use only - */ - @Retention(RetentionPolicy.RUNTIME) - protected @interface OpenCLMapping { - String mapTo() default ""; - - boolean atomic32() default false; - - boolean atomic64() default false; - } - - public abstract class Entry { - public abstract void run(); - - public Kernel execute(Range _range) { - return (Kernel.this.execute("foo", _range, 1)); - } - } - - /** - * @deprecated It is no longer recommended that {@code EXECUTION_MODE}s are used, as a more sophisticated {@link com.aparapi.device.Device} - * preference mechanism is in place, see {@link com.aparapi.internal.kernel.KernelManager}. Though {@link #setExecutionMode(EXECUTION_MODE)} - * is still honored, the default EXECUTION_MODE is now {@link EXECUTION_MODE#AUTO}, which indicates that the KernelManager - * will determine execution behaviours. - * - * <p> - * The <i>execution mode</i> ENUM enumerates the possible modes of executing a kernel. - * One can request a mode of execution using the values below, and query a kernel after it first executes to - * determine how it executed. - * - * <p> - * Aparapi supports 5 execution modes. Default is GPU. - * <ul> - * <table> - * <tr><th align="left">Enum value</th><th align="left">Execution</th></tr> - * <tr><td><code><b>GPU</b></code></td><td>Execute using OpenCL on first available GPU device</td></tr> - * <tr><td><code><b>ACC</b></code></td><td>Execute using OpenCL on first available Accelerator device</td></tr> - * <tr><td><code><b>CPU</b></code></td><td>Execute using OpenCL on first available CPU device</td></tr> - * <tr><td><code><b>JTP</b></code></td><td>Execute using a Java Thread Pool (one thread spawned per available core)</td></tr> - * <tr><td><code><b>SEQ</b></code></td><td>Execute using a single loop. This is useful for debugging but will be less - * performant than the other modes</td></tr> - * </table> - * </ul> - * <p> - * To request that a kernel is executed in a specific mode, call <code>Kernel.setExecutionMode(EXECUTION_MODE)</code> before the - * kernel first executes. - * <p> - * <blockquote><pre> - * int[] values = new int[1024]; - * // fill values array - * SquareKernel kernel = new SquareKernel(values); - * kernel.setExecutionMode(Kernel.EXECUTION_MODE.JTP); - * kernel.execute(values.length); - * </pre></blockquote> - * <p> -<<<<<<< HEAD:src/main/java/com/aparapi/Kernel.java - * Alternatively, the property <code>com.aparapi.executionMode</code> can be set to one of <code>JTP,GPU,ACC,CPU,SEQ</code> - * when an application is launched. - * <p><blockquote><pre> - * java -classpath ....;aparapi.jar -Dcom.aparapi.executionMode=GPU MyApplication -======= - * Alternatively, the property <code>com.amd.aparapi.executionMode</code> can be set to one of <code>JTP,GPU,ACC,CPU,SEQ</code> - * when an application is launched. - * <p><blockquote><pre> - * java -classpath ....;aparapi.jar -Dcom.amd.aparapi.executionMode=GPU MyApplication ->>>>>>> b118aad... added method to set execution mode without any fallback:com.amd.aparapi/src/java/com/amd/aparapi/Kernel.java - * </pre></blockquote><p> - * Generally setting the execution mode is not recommended (it is best to let Aparapi decide automatically) but the option - * provides a way to compare a kernel's performance under multiple execution modes. - * - * @author gfrost AMD Javalabs - * @version Alpha, 21/09/2010 - */ - @Deprecated - public static enum EXECUTION_MODE { - /** - * - */ - AUTO, - /** - * A dummy value to indicate an unknown state. - */ - NONE, - /** - * The value representing execution on a GPU device via OpenCL. - */ - GPU, - /** - * The value representing execution on a CPU device via OpenCL. - * <p> - * <b>Note</b> not all OpenCL implementations support OpenCL compute on the CPU. - */ - CPU, - /** - * The value representing execution on a Java Thread Pool. - * <p> - * By default one Java thread is started for each available core and each core will execute <code>globalSize/cores</code> work items. - * This creates a total of <code>globalSize%cores</code> threads to complete the work. - * Choose suitable values for <code>globalSize</code> to minimize the number of threads that are spawned. - */ - JTP, - /** - * The value representing execution sequentially in a single loop. - * <p> - * This is meant to be used for debugging a kernel. - */ - SEQ, - /** - * The value representing execution on an accelerator device (Xeon Phi) via OpenCL. - */ - ACC; - - /** - * @deprecated See {@link EXECUTION_MODE}. - */ - @Deprecated - static LinkedHashSet<EXECUTION_MODE> getDefaultExecutionModes() { - LinkedHashSet<EXECUTION_MODE> defaultExecutionModes = new LinkedHashSet<EXECUTION_MODE>(); - - if (OpenCLLoader.isOpenCLAvailable()) { - defaultExecutionModes.add(GPU); - defaultExecutionModes.add(JTP); - } else { - defaultExecutionModes.add(JTP); - } - - final String executionMode = Config.executionMode; - - if (executionMode != null) { - try { - LinkedHashSet<EXECUTION_MODE> requestedExecutionModes; - requestedExecutionModes = EXECUTION_MODE.getExecutionModeFromString(executionMode); - logger.fine("requested execution mode ="); - for (final EXECUTION_MODE mode : requestedExecutionModes) { - logger.fine(" " + mode); - } - if ((OpenCLLoader.isOpenCLAvailable() && EXECUTION_MODE.anyOpenCL(requestedExecutionModes)) - || !EXECUTION_MODE.anyOpenCL(requestedExecutionModes)) { - defaultExecutionModes = requestedExecutionModes; - } - } catch (final Throwable t) { - // we will take the default - } - } - - logger.info("default execution modes = " + defaultExecutionModes); - - for (final EXECUTION_MODE e : defaultExecutionModes) { - logger.info("SETTING DEFAULT MODE: " + e.toString()); - } - - return (defaultExecutionModes); - } - - static LinkedHashSet<EXECUTION_MODE> getExecutionModeFromString(String executionMode) { - final LinkedHashSet<EXECUTION_MODE> executionModes = new LinkedHashSet<EXECUTION_MODE>(); - for (final String mode : executionMode.split(",")) { - executionModes.add(valueOf(mode.toUpperCase())); - } - return executionModes; - } - - static EXECUTION_MODE getFallbackExecutionMode() { - final EXECUTION_MODE defaultFallbackExecutionMode = JTP; - logger.info("fallback execution mode = " + defaultFallbackExecutionMode); - return (defaultFallbackExecutionMode); - } - - static boolean anyOpenCL(LinkedHashSet<EXECUTION_MODE> _executionModes) { - for (final EXECUTION_MODE mode : _executionModes) { - if ((mode == GPU) || (mode == ACC) || (mode == CPU)) { - return true; - } - } - return false; - } - - public boolean isOpenCL() { - return (this == GPU) || (this == ACC) || (this == CPU); - } - }; - - private KernelRunner kernelRunner = null; - - private boolean autoCleanUpArrays = false; - - private KernelState kernelState = new KernelState(); - - /** - * This class is for internal Kernel state management<p> - * NOT INTENDED FOR USE BY USERS - */ - public final class KernelState { - - private int[] globalIds = new int[] {0, 0, 0}; - - private int[] localIds = new int[] {0, 0, 0}; - - private int[] groupIds = new int[] {0, 0, 0}; - - private Range range; - - private int passId; - - private volatile CyclicBarrier localBarrier; - - private boolean localBarrierDisabled; - - /** - * Default constructor - */ - protected KernelState() { - - } - - /** - * Copy constructor - */ - protected KernelState(KernelState kernelState) { - globalIds = kernelState.getGlobalIds(); - localIds = kernelState.getLocalIds(); - groupIds = kernelState.getGroupIds(); - range = kernelState.getRange(); - passId = kernelState.getPassId(); - localBarrier = kernelState.getLocalBarrier(); - } - - /** - * @return the globalIds - */ - public int[] getGlobalIds() { - return globalIds; - } - - /** - * @param globalIds the globalIds to set - */ - public void setGlobalIds(int[] globalIds) { - this.globalIds = globalIds; - } - - /** - * Set a specific index value - * - * @param _index - * @param value - */ - public void setGlobalId(int _index, int value) { - globalIds[_index] = value; - } - - /** - * @return the localIds - */ - public int[] getLocalIds() { - return localIds; - } - - /** - * @param localIds the localIds to set - */ - public void setLocalIds(int[] localIds) { - this.localIds = localIds; - } - - /** - * Set a specific index value - * - * @param _index - * @param value - */ - public void setLocalId(int _index, int value) { - localIds[_index] = value; - } - - /** - * @return the groupIds - */ - public int[] getGroupIds() { - return groupIds; - } - - /** - * @param groupIds the groupIds to set - */ - public void setGroupIds(int[] groupIds) { - this.groupIds = groupIds; - } - - /** - * Set a specific index value - * - * @param _index - * @param value - */ - public void setGroupId(int _index, int value) { - groupIds[_index] = value; - } - - /** - * @return the range - */ - public Range getRange() { - return range; - } - - /** - * @param range the range to set - */ - public void setRange(Range range) { - this.range = range; - } - - /** - * @return the passId - */ - public int getPassId() { - return passId; - } - - /** - * @param passId the passId to set - */ - public void setPassId(int passId) { - this.passId = passId; - } - - /** - * @return the localBarrier - */ - public CyclicBarrier getLocalBarrier() { - return localBarrier; - } - - /** - * @param localBarrier the localBarrier to set - */ - public void setLocalBarrier(CyclicBarrier localBarrier) { - this.localBarrier = localBarrier; - } - - public void awaitOnLocalBarrier() { - if (!localBarrierDisabled) { - try { - kernelState.getLocalBarrier().await(); - } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final BrokenBarrierException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - public void disableLocalBarrier() { - localBarrierDisabled = true; - } - } - - /** - * Determine the globalId of an executing kernel. - * <p> - * The kernel implementation uses the globalId to determine which of the executing kernels (in the global domain space) this invocation is expected to deal with. - * <p> - * For example in a <code>SquareKernel</code> implementation: - * <p> - * <blockquote><pre> - * class SquareKernel extends Kernel{ - * private int values[]; - * private int squares[]; - * public SquareKernel(int values[]){ - * this.values = values; - * squares = new int[values.length]; - * } - * public void run() { - * int gid = getGlobalID(); - * squares[gid] = values[gid]*values[gid]; - * } - * public int[] getSquares(){ - * return(squares); - * } - * } - * </pre></blockquote> - * <p> - * Each invocation of <code>SquareKernel.run()</code> retrieves it's globalId by calling <code>getGlobalId()</code>, and then computes the value of <code>square[gid]</code> for a given value of <code>value[gid]</code>. - * <p> - * @return The globalId for the Kernel being executed - * - * @see #getLocalId() - * @see #getGroupId() - * @see #getGlobalSize() - * @see #getNumGroups() - * @see #getLocalSize() - */ - - @OpenCLDelegate - protected final int getGlobalId() { - return getGlobalId(0); - } - - @OpenCLDelegate - protected final int getGlobalId(int _dim) { - return kernelState.getGlobalIds()[_dim]; - } - - /* - @OpenCLDelegate protected final int getGlobalX() { - return (getGlobalId(0)); - } - - @OpenCLDelegate protected final int getGlobalY() { - return (getGlobalId(1)); - } - - @OpenCLDelegate protected final int getGlobalZ() { - return (getGlobalId(2)); - } - */ - /** - * Determine the groupId of an executing kernel. - * <p> - * When a <code>Kernel.execute(int globalSize)</code> is invoked for a particular kernel, the runtime will break the work into various 'groups'. - * <p> - * A kernel can use <code>getGroupId()</code> to determine which group a kernel is currently - * dispatched to - * <p> - * The following code would capture the groupId for each kernel and map it against globalId. - * <blockquote><pre> - * final int[] groupIds = new int[1024]; - * Kernel kernel = new Kernel(){ - * public void run() { - * int gid = getGlobalId(); - * groupIds[gid] = getGroupId(); - * } - * }; - * kernel.execute(groupIds.length); - * for (int i=0; i< values.length; i++){ - * System.out.printf("%4d %4d\n", i, groupIds[i]); - * } - * </pre></blockquote> - * - * @see #getLocalId() - * @see #getGlobalId() - * @see #getGlobalSize() - * @see #getNumGroups() - * @see #getLocalSize() - * - * @return The groupId for this Kernel being executed - */ - @OpenCLDelegate - protected final int getGroupId() { - return getGroupId(0); - } - - @OpenCLDelegate - protected final int getGroupId(int _dim) { - return kernelState.getGroupIds()[_dim]; - } - - /* - @OpenCLDelegate protected final int getGroupX() { - return (getGroupId(0)); - } - - @OpenCLDelegate protected final int getGroupY() { - return (getGroupId(1)); - } - - @OpenCLDelegate protected final int getGroupZ() { - return (getGroupId(2)); - } - */ - /** - * Determine the passId of an executing kernel. - * <p> - * When a <code>Kernel.execute(int globalSize, int passes)</code> is invoked for a particular kernel, the runtime will break the work into various 'groups'. - * <p> - * A kernel can use <code>getPassId()</code> to determine which pass we are in. This is ideal for 'reduce' type phases - * - * @see #getLocalId() - * @see #getGlobalId() - * @see #getGlobalSize() - * @see #getNumGroups() - * @see #getLocalSize() - * - * @return The groupId for this Kernel being executed - */ - @OpenCLDelegate - protected final int getPassId() { - return kernelState.getPassId(); - } - - /** - * Determine the local id of an executing kernel. - * <p> - * When a <code>Kernel.execute(int globalSize)</code> is invoked for a particular kernel, the runtime will break the work into - * various 'groups'. - * <code>getLocalId()</code> can be used to determine the relative id of the current kernel within a specific group. - * <p> - * The following code would capture the groupId for each kernel and map it against globalId. - * <blockquote><pre> - * final int[] localIds = new int[1024]; - * Kernel kernel = new Kernel(){ - * public void run() { - * int gid = getGlobalId(); - * localIds[gid] = getLocalId(); - * } - * }; - * kernel.execute(localIds.length); - * for (int i=0; i< values.length; i++){ - * System.out.printf("%4d %4d\n", i, localIds[i]); - * } - * </pre></blockquote> - * - * @see #getGroupId() - * @see #getGlobalId() - * @see #getGlobalSize() - * @see #getNumGroups() - * @see #getLocalSize() - * - * @return The local id for this Kernel being executed - */ - @OpenCLDelegate - protected final int getLocalId() { - return getLocalId(0); - } - - @OpenCLDelegate - protected final int getLocalId(int _dim) { - return kernelState.getLocalIds()[_dim]; - } - - /* - @OpenCLDelegate protected final int getLocalX() { - return (getLocalId(0)); - } - - @OpenCLDelegate protected final int getLocalY() { - return (getLocalId(1)); - } - - @OpenCLDelegate protected final int getLocalZ() { - return (getLocalId(2)); - } - */ - /** - * Determine the size of the group that an executing kernel is a member of. - * <p> - * When a <code>Kernel.execute(int globalSize)</code> is invoked for a particular kernel, the runtime will break the work into - * various 'groups'. <code>getLocalSize()</code> allows a kernel to determine the size of the current group. - * <p> - * Note groups may not all be the same size. In particular, if <code>(global size)%(# of compute devices)!=0</code>, the runtime can choose to dispatch kernels to - * groups with differing sizes. - * - * @see #getGroupId() - * @see #getGlobalId() - * @see #getGlobalSize() - * @see #getNumGroups() - * @see #getLocalSize() - * - * @return The size of the currently executing group. - */ - @OpenCLDelegate - protected final int getLocalSize() { - return kernelState.getRange().getLocalSize(0); - } - - @OpenCLDelegate - protected final int getLocalSize(int _dim) { - return kernelState.getRange().getLocalSize(_dim); - } - - /* - @OpenCLDelegate protected final int getLocalWidth() { - return (range.getLocalSize(0)); - } - - @OpenCLDelegate protected final int getLocalHeight() { - return (range.getLocalSize(1)); - } - - @OpenCLDelegate protected final int getLocalDepth() { - return (range.getLocalSize(2)); - } - */ - /** - * Determine the value that was passed to <code>Kernel.execute(int globalSize)</code> method. - * - * @see #getGroupId() - * @see #getGlobalId() - * @see #getNumGroups() - * @see #getLocalSize() - * - * @return The value passed to <code>Kernel.execute(int globalSize)</code> causing the current execution. - */ - @OpenCLDelegate - protected final int getGlobalSize() { - return kernelState.getRange().getGlobalSize(0); - } - - @OpenCLDelegate - protected final int getGlobalSize(int _dim) { - return kernelState.getRange().getGlobalSize(_dim); - } - - /* - @OpenCLDelegate protected final int getGlobalWidth() { - return (range.getGlobalSize(0)); - } - - @OpenCLDelegate protected final int getGlobalHeight() { - return (range.getGlobalSize(1)); - } - - @OpenCLDelegate protected final int getGlobalDepth() { - return (range.getGlobalSize(2)); - } - */ - /** - * Determine the number of groups that will be used to execute a kernel - * <p> - * When <code>Kernel.execute(int globalSize)</code> is invoked, the runtime will split the work into - * multiple 'groups'. <code>getNumGroups()</code> returns the total number of groups that will be used. - * - * @see #getGroupId() - * @see #getGlobalId() - * @see #getGlobalSize() - * @see #getNumGroups() - * @see #getLocalSize() - * - * @return The number of groups that kernels will be dispatched into. - */ - @OpenCLDelegate - protected final int getNumGroups() { - return kernelState.getRange().getNumGroups(0); - } - - @OpenCLDelegate - protected final int getNumGroups(int _dim) { - return kernelState.getRange().getNumGroups(_dim); - } - - /* - @OpenCLDelegate protected final int getNumGroupsWidth() { - return (range.getGroups(0)); - } - - @OpenCLDelegate protected final int getNumGroupsHeight() { - return (range.getGroups(1)); - } - - @OpenCLDelegate protected final int getNumGroupsDepth() { - return (range.getGroups(2)); - } - */ - /** - * The entry point of a kernel. - * - * <p> - * Every kernel must override this method. - */ - public abstract void run(); - - /** False by default. In the event that all preferred devices fail to execute a kernel, it is possible to supply an alternate (possibly non-parallel) - * execution algorithm by overriding this method to return true, and overriding {@link #executeFallbackAlgorithm(Range, int)} with the alternate - * algorithm. - */ - public boolean hasFallbackAlgorithm() { - return false; - } - - /** If {@link #hasFallbackAlgorithm()} has been overriden to return true, this method should be overriden so as to - * apply a single pass of the kernel's logic to the entire _range. - * - * <p> - * This is not normally required, as fallback to {@link JavaDevice#THREAD_POOL} will implement the algorithm in parallel. However - * in the event that thread pool execution may be prohibitively slow, this method might implement a "quick and dirty" approximation - * to the desired result (for example, a simple box-blur as opposed to a gaussian blur in an image processing application). - */ - public void executeFallbackAlgorithm(Range _range, int _passId) { - // nothing - } - - /** - * Invoking this method flags that once the current pass is complete execution should be abandoned. Due to the complexity of intercommunication - * between java (or C) and executing OpenCL, this is the best we can do for general cancellation of execution at present. OpenCL 2.0 should introduce - * pipe mechanisms which will support mid-pass cancellation easily. - * - * <p> - * Note that in the case of thread-pool/pure java execution we could do better already, using Thread.interrupt() (and/or other means) to abandon - * execution mid-pass. However at present this is not attempted. - * - * @see #execute(int, int) - * @see #execute(Range, int) - * @see #execute(String, Range, int) - */ - public void cancelMultiPass() { - if (kernelRunner == null) { - return; - } - kernelRunner.cancelMultiPass(); - } - - public int getCancelState() { - return kernelRunner == null ? KernelRunner.CANCEL_STATUS_FALSE : kernelRunner.getCancelState(); - } - - /** - * @see KernelRunner#getCurrentPass() - */ - public int getCurrentPass() { - if (kernelRunner == null) { - return KernelRunner.PASS_ID_COMPLETED_EXECUTION; - } - return kernelRunner.getCurrentPass(); - } - - /** - * @see KernelRunner#isExecuting() - */ - public boolean isExecuting() { - if (kernelRunner == null) { - return false; - } - return kernelRunner.isExecuting(); - } - - /** - * When using a Java Thread Pool Aparapi uses clone to copy the initial instance to each thread. - * - * <p> - * If you choose to override <code>clone()</code> you are responsible for delegating to <code>super.clone();</code> - */ - @Override - public Kernel clone() { - try { - final Kernel worker = (Kernel) super.clone(); - - // We need to be careful to also clone the KernelState - worker.kernelState = worker.new KernelState(kernelState); // Qualified copy constructor - - worker.kernelState.setGroupIds(new int[] {0, 0, 0}); - - worker.kernelState.setLocalIds(new int[] {0, 0, 0}); - - worker.kernelState.setGlobalIds(new int[] {0, 0, 0}); - - return worker; - } catch (final CloneNotSupportedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return (null); - } - } - - /** - * Delegates to either {@link java.lang.Math#acos(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param a value to delegate to {@link java.lang.Math#acos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(float)</a></code> - * @return {@link java.lang.Math#acos(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(float)</a></code> - * - * @see java.lang.Math#acos(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(float)</a></code> - */ - @OpenCLMapping(mapTo = "acos") - protected float acos(float a) { - return (float) Math.acos(a); - } - - /** - * Delegates to either {@link java.lang.Math#acos(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param a value to delegate to {@link java.lang.Math#acos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(double)</a></code> - * @return {@link java.lang.Math#acos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(double)</a></code> - * - * @see java.lang.Math#acos(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(double)</a></code> - */ - @OpenCLMapping(mapTo = "acos") - protected double acos(double a) { - return Math.acos(a); - } - - /** - * Delegates to either {@link java.lang.Math#asin(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#asin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(float)</a></code> - * @return {@link java.lang.Math#asin(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(float)</a></code> - * - * @see java.lang.Math#asin(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(float)</a></code> - */ - @OpenCLMapping(mapTo = "asin") - protected float asin(float _f) { - return (float) Math.asin(_f); - } - - /** - * Delegates to either {@link java.lang.Math#asin(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#asin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(double)</a></code> - * @return {@link java.lang.Math#asin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(double)</a></code> - * - * @see java.lang.Math#asin(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(double)</a></code> - */ - @OpenCLMapping(mapTo = "asin") - protected double asin(double _d) { - return Math.asin(_d); - } - - /** - * Delegates to either {@link java.lang.Math#atan(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#atan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(float)</a></code> - * @return {@link java.lang.Math#atan(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(float)</a></code> - * - * @see java.lang.Math#atan(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(float)</a></code> - */ - @OpenCLMapping(mapTo = "atan") - protected float atan(float _f) { - return (float) Math.atan(_f); - } - - /** - * Delegates to either {@link java.lang.Math#atan(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#atan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(double)</a></code> - * @return {@link java.lang.Math#atan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(double)</a></code> - * - * @see java.lang.Math#atan(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(double)</a></code> - */ - @OpenCLMapping(mapTo = "atan") - protected double atan(double _d) { - return Math.atan(_d); - } - - /** - * Delegates to either {@link java.lang.Math#atan2(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(float, float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f1 value to delegate to first argument of {@link java.lang.Math#atan2(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(float, float)</a></code> - * @param _f2 value to delegate to second argument of {@link java.lang.Math#atan2(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(float, float)</a></code> - * @return {@link java.lang.Math#atan2(double, double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(float, float)</a></code> - * - * @see java.lang.Math#atan2(double, double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(float, float)</a></code> - */ - @OpenCLMapping(mapTo = "atan2") - protected float atan2(float _f1, float _f2) { - return (float) Math.atan2(_f1, _f2); - } - - /** - * Delegates to either {@link java.lang.Math#atan2(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(double, double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d1 value to delegate to first argument of {@link java.lang.Math#atan2(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(double, double)</a></code> - * @param _d2 value to delegate to second argument of {@link java.lang.Math#atan2(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(double, double)</a></code> - * @return {@link java.lang.Math#atan2(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(double, double)</a></code> - * - * @see java.lang.Math#atan2(double, double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(double, double)</a></code> - */ - @OpenCLMapping(mapTo = "atan2") - protected double atan2(double _d1, double _d2) { - return Math.atan2(_d1, _d2); - } - - /** - * Delegates to either {@link java.lang.Math#ceil(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#ceil(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(float)</a></code> - * @return {@link java.lang.Math#ceil(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(float)</a></code> - * - * @see java.lang.Math#ceil(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(float)</a></code> - */ - @OpenCLMapping(mapTo = "ceil") - protected float ceil(float _f) { - return (float) Math.ceil(_f); - } - - /** - * Delegates to either {@link java.lang.Math#ceil(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#ceil(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(double)</a></code> - * @return {@link java.lang.Math#ceil(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(double)</a></code> - * - * @see java.lang.Math#ceil(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(double)</a></code> - */ - @OpenCLMapping(mapTo = "ceil") - protected double ceil(double _d) { - return Math.ceil(_d); - } - - /** - * Delegates to either {@link java.lang.Math#cos(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#cos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(float)</a></code> - * @return {@link java.lang.Math#cos(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(float)</a></code> - * - * @see java.lang.Math#cos(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(float)</a></code> - */ - @OpenCLMapping(mapTo = "cos") - protected float cos(float _f) { - return (float) Math.cos(_f); - } - - /** - * Delegates to either {@link java.lang.Math#cos(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#cos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(double)</a></code> - * @return {@link java.lang.Math#cos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(double)</a></code> - * - * @see java.lang.Math#cos(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(double)</a></code> - */ - @OpenCLMapping(mapTo = "cos") - protected double cos(double _d) { - return Math.cos(_d); - } - - /** - * Delegates to either {@link java.lang.Math#exp(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#exp(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(float)</a></code> - * @return {@link java.lang.Math#exp(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(float)</a></code> - * - * @see java.lang.Math#exp(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(float)</a></code> - */ - @OpenCLMapping(mapTo = "exp") - protected float exp(float _f) { - return (float) Math.exp(_f); - } - - /** - * Delegates to either {@link java.lang.Math#exp(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#exp(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(double)</a></code> - * @return {@link java.lang.Math#exp(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(double)</a></code> - * - * @see java.lang.Math#exp(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(double)</a></code> - */ - @OpenCLMapping(mapTo = "exp") - protected double exp(double _d) { - return Math.exp(_d); - } - - /** - * Delegates to either {@link java.lang.Math#abs(float)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#abs(float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(float)</a></code> - * @return {@link java.lang.Math#abs(float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(float)</a></code> - * - * @see java.lang.Math#abs(float) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(float)</a></code> - */ - @OpenCLMapping(mapTo = "fabs") - protected float abs(float _f) { - return Math.abs(_f); - } - - /** - * Delegates to either {@link java.lang.Math#abs(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#abs(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(double)</a></code> - * @return {@link java.lang.Math#abs(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(double)</a></code> - * - * @see java.lang.Math#abs(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(double)</a></code> - */ - @OpenCLMapping(mapTo = "fabs") - protected double abs(double _d) { - return Math.abs(_d); - } - - /** - * Delegates to either {@link java.lang.Math#abs(int)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(int)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param n value to delegate to {@link java.lang.Math#abs(int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(int)</a></code> - * @return {@link java.lang.Math#abs(int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(int)</a></code> - * - * @see java.lang.Math#abs(int) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(int)</a></code> - */ - @OpenCLMapping(mapTo = "abs") - protected int abs(int n) { - return Math.abs(n); - } - - /** - * Delegates to either {@link java.lang.Math#abs(long)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(long)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param n value to delegate to {@link java.lang.Math#abs(long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(long)</a></code> - * @return {@link java.lang.Math#abs(long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">abs(long)</a></code> - * - * @see java.lang.Math#abs(long) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(long)</a></code> - */ - @OpenCLMapping(mapTo = "abs") - protected long abs(long n) { - return Math.abs(n); - } - - /** - * Delegates to either {@link java.lang.Math#floor(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">floor(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#floor(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(float)</a></code> - * @return {@link java.lang.Math#floor(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(float)</a></code> - * - * @see java.lang.Math#floor(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(float)</a></code> - */ - @OpenCLMapping(mapTo = "floor") - protected float floor(float _f) { - return (float) Math.floor(_f); - } - - /** - * Delegates to either {@link java.lang.Math#floor(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">floor(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#floor(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(double)</a></code> - * @return {@link java.lang.Math#floor(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(double)</a></code> - * - * @see java.lang.Math#floor(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(double)</a></code> - */ - @OpenCLMapping(mapTo = "floor") - protected double floor(double _d) { - return Math.floor(_d); - } - - /** - * Delegates to either {@link java.lang.Math#max(float, float)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(float, float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f1 value to delegate to first argument of {@link java.lang.Math#max(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(float, float)</a></code> - * @param _f2 value to delegate to second argument of {@link java.lang.Math#max(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(float, float)</a></code> - * @return {@link java.lang.Math#max(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(float, float)</a></code> - * - * @see java.lang.Math#max(float, float) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(float, float)</a></code> - */ - @OpenCLMapping(mapTo = "fmax") - protected float max(float _f1, float _f2) { - return Math.max(_f1, _f2); - } - - /** - * Delegates to either {@link java.lang.Math#max(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(double, double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d1 value to delegate to first argument of {@link java.lang.Math#max(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(double, double)</a></code> - * @param _d2 value to delegate to second argument of {@link java.lang.Math#max(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(double, double)</a></code> - * @return {@link java.lang.Math#max(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(double, double)</a></code> - * - * @see java.lang.Math#max(double, double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(double, double)</a></code> - */ - @OpenCLMapping(mapTo = "fmax") - protected double max(double _d1, double _d2) { - return Math.max(_d1, _d2); - } - - /** - * Delegates to either {@link java.lang.Math#max(int, int)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(int, int)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param n1 value to delegate to {@link java.lang.Math#max(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(int, int)</a></code> - * @param n2 value to delegate to {@link java.lang.Math#max(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(int, int)</a></code> - * @return {@link java.lang.Math#max(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(int, int)</a></code> - * - * @see java.lang.Math#max(int, int) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(int, int)</a></code> - */ - @OpenCLMapping(mapTo = "max") - protected int max(int n1, int n2) { - return Math.max(n1, n2); - } - - /** - * Delegates to either {@link java.lang.Math#max(long, long)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(long, long)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param n1 value to delegate to first argument of {@link java.lang.Math#max(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(long, long)</a></code> - * @param n2 value to delegate to second argument of {@link java.lang.Math#max(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(long, long)</a></code> - * @return {@link java.lang.Math#max(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(long, long)</a></code> - * - * @see java.lang.Math#max(long, long) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(long, long)</a></code> - */ - @OpenCLMapping(mapTo = "max") - protected long max(long n1, long n2) { - return Math.max(n1, n2); - } - - /** - * Delegates to either {@link java.lang.Math#min(float, float)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(float, float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f1 value to delegate to first argument of {@link java.lang.Math#min(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(float, float)</a></code> - * @param _f2 value to delegate to second argument of {@link java.lang.Math#min(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(float, float)</a></code> - * @return {@link java.lang.Math#min(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(float, float)</a></code> - * - * @see java.lang.Math#min(float, float) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(float, float)</a></code> - */ - @OpenCLMapping(mapTo = "fmin") - protected float min(float _f1, float _f2) { - return Math.min(_f1, _f2); - } - - /** - * Delegates to either {@link java.lang.Math#min(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(double, double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d1 value to delegate to first argument of {@link java.lang.Math#min(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(double, double)</a></code> - * @param _d2 value to delegate to second argument of {@link java.lang.Math#min(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(double, double)</a></code> - * @return {@link java.lang.Math#min(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(double, double)</a></code> - * - * @see java.lang.Math#min(double, double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(double, double)</a></code> - */ - @OpenCLMapping(mapTo = "fmin") - protected double min(double _d1, double _d2) { - return Math.min(_d1, _d2); - } - - /** - * Delegates to either {@link java.lang.Math#min(int, int)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(int, int)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param n1 value to delegate to first argument of {@link java.lang.Math#min(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(int, int)</a></code> - * @param n2 value to delegate to second argument of {@link java.lang.Math#min(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(int, int)</a></code> - * @return {@link java.lang.Math#min(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(int, int)</a></code> - * - * @see java.lang.Math#min(int, int) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(int, int)</a></code> - */ - @OpenCLMapping(mapTo = "min") - protected int min(int n1, int n2) { - return Math.min(n1, n2); - } - - /** - * Delegates to either {@link java.lang.Math#min(long, long)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(long, long)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param n1 value to delegate to first argument of {@link java.lang.Math#min(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(long, long)</a></code> - * @param n2 value to delegate to second argument of {@link java.lang.Math#min(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(long, long)</a></code> - * @return {@link java.lang.Math#min(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(long, long)</a></code> - * - * @see java.lang.Math#min(long, long) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(long, long)</a></code> - */ - @OpenCLMapping(mapTo = "min") - protected long min(long n1, long n2) { - return Math.min(n1, n2); - } - - /** - * Delegates to either {@link java.lang.Math#log(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#log(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(float)</a></code> - * @return {@link java.lang.Math#log(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(float)</a></code> - * - * @see java.lang.Math#log(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(float)</a></code> - */ - @OpenCLMapping(mapTo = "log") - protected float log(float _f) { - return (float) Math.log(_f); - } - - /** - * Delegates to either {@link java.lang.Math#log(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#log(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(double)</a></code> - * @return {@link java.lang.Math#log(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(double)</a></code> - * - * @see java.lang.Math#log(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(double)</a></code> - */ - @OpenCLMapping(mapTo = "log") - protected double log(double _d) { - return Math.log(_d); - } - - /** - * Delegates to either {@link java.lang.Math#pow(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(float, float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f1 value to delegate to first argument of {@link java.lang.Math#pow(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(float, float)</a></code> - * @param _f2 value to delegate to second argument of {@link java.lang.Math#pow(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(float, float)</a></code> - * @return {@link java.lang.Math#pow(double, double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(float, float)</a></code> - * - * @see java.lang.Math#pow(double, double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(float, float)</a></code> - */ - @OpenCLMapping(mapTo = "pow") - protected float pow(float _f1, float _f2) { - return (float) Math.pow(_f1, _f2); - } - - /** - * Delegates to either {@link java.lang.Math#pow(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(double, double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d1 value to delegate to first argument of {@link java.lang.Math#pow(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(double, double)</a></code> - * @param _d2 value to delegate to second argument of {@link java.lang.Math#pow(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(double, double)</a></code> - * @return {@link java.lang.Math#pow(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(double, double)</a></code> - * - * @see java.lang.Math#pow(double, double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(double, double)</a></code> - */ - @OpenCLMapping(mapTo = "pow") - protected double pow(double _d1, double _d2) { - return Math.pow(_d1, _d2); - } - - /** - * Delegates to either {@link java.lang.Math#IEEEremainder(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(float, float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f1 value to delegate to first argument of {@link java.lang.Math#IEEEremainder(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(float, float)</a></code> - * @param _f2 value to delegate to second argument of {@link java.lang.Math#IEEEremainder(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(float, float)</a></code> - * @return {@link java.lang.Math#IEEEremainder(double, double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(float, float)</a></code> - * - * @see java.lang.Math#IEEEremainder(double, double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(float, float)</a></code> - */ - @OpenCLMapping(mapTo = "remainder") - protected float IEEEremainder(float _f1, float _f2) { - return (float) Math.IEEEremainder(_f1, _f2); - } - - /** - * Delegates to either {@link java.lang.Math#IEEEremainder(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(double, double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d1 value to delegate to first argument of {@link java.lang.Math#IEEEremainder(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(double, double)</a></code> - * @param _d2 value to delegate to second argument of {@link java.lang.Math#IEEEremainder(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(double, double)</a></code> - * @return {@link java.lang.Math#IEEEremainder(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(double, double)</a></code> - * - * @see java.lang.Math#IEEEremainder(double, double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(double, double)</a></code> - */ - @OpenCLMapping(mapTo = "remainder") - protected double IEEEremainder(double _d1, double _d2) { - return Math.IEEEremainder(_d1, _d2); - } - - /** - * Delegates to either {@link java.lang.Math#toRadians(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#toRadians(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(float)</a></code> - * @return {@link java.lang.Math#toRadians(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(float)</a></code> - * - * @see java.lang.Math#toRadians(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(float)</a></code> - */ - @OpenCLMapping(mapTo = "radians") - protected float toRadians(float _f) { - return (float) Math.toRadians(_f); - } - - /** - * Delegates to either {@link java.lang.Math#toRadians(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#toRadians(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(double)</a></code> - * @return {@link java.lang.Math#toRadians(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(double)</a></code> - * - * @see java.lang.Math#toRadians(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(double)</a></code> - */ - @OpenCLMapping(mapTo = "radians") - protected double toRadians(double _d) { - return Math.toRadians(_d); - } - - /** - * Delegates to either {@link java.lang.Math#toDegrees(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#toDegrees(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(float)</a></code> - * @return {@link java.lang.Math#toDegrees(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(float)</a></code> - * - * @see java.lang.Math#toDegrees(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(float)</a></code> - */ - @OpenCLMapping(mapTo = "degrees") - protected float toDegrees(float _f) { - return (float) Math.toDegrees(_f); - } - - /** - * Delegates to either {@link java.lang.Math#toDegrees(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#toDegrees(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(double)</a></code> - * @return {@link java.lang.Math#toDegrees(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(double)</a></code> - * - * @see java.lang.Math#toDegrees(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(double)</a></code> - */ - @OpenCLMapping(mapTo = "degrees") - protected double toDegrees(double _d) { - return Math.toDegrees(_d); - } - - /** - * Delegates to either {@link java.lang.Math#rint(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#rint(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(float)</a></code> - * @return {@link java.lang.Math#rint(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(float)</a></code> - * - * @see java.lang.Math#rint(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(float)</a></code> - */ - @OpenCLMapping(mapTo = "rint") - protected float rint(float _f) { - return (float) Math.rint(_f); - } - - /** - * Delegates to either {@link java.lang.Math#rint(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#rint(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(double)</a></code> - * @return {@link java.lang.Math#rint(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(double)</a></code> - * - * @see java.lang.Math#rint(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(double)</a></code> - */ - @OpenCLMapping(mapTo = "rint") - protected double rint(double _d) { - return Math.rint(_d); - } - - /** - * Delegates to either {@link java.lang.Math#round(float)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#round(float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(float)</a></code> - * @return {@link java.lang.Math#round(float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(float)</a></code> - * - * @see java.lang.Math#round(float) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(float)</a></code> - */ - @OpenCLMapping(mapTo = "round") - protected int round(float _f) { - return Math.round(_f); - } - - /** - * Delegates to either {@link java.lang.Math#round(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#round(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(double)</a></code> - * @return {@link java.lang.Math#round(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(double)</a></code> - * - * @see java.lang.Math#round(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(double)</a></code> - */ - @OpenCLMapping(mapTo = "round") - protected long round(double _d) { - return Math.round(_d); - } - - /** - * Delegates to either {@link java.lang.Math#sin(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#sin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(float)</a></code> - * @return {@link java.lang.Math#sin(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(float)</a></code> - * - * @see java.lang.Math#sin(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(float)</a></code> - */ - @OpenCLMapping(mapTo = "sin") - protected float sin(float _f) { - return (float) Math.sin(_f); - } - - /** - * Delegates to either {@link java.lang.Math#sin(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#sin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(double)</a></code> - * @return {@link java.lang.Math#sin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(double)</a></code> - * - * @see java.lang.Math#sin(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(double)</a></code> - */ - @OpenCLMapping(mapTo = "sin") - protected double sin(double _d) { - return Math.sin(_d); - } - - /** - * Delegates to either {@link java.lang.Math#sqrt(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#sqrt(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(float)</a></code> - * @return {@link java.lang.Math#sqrt(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(float)</a></code> - * - * @see java.lang.Math#sqrt(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(float)</a></code> - */ - @OpenCLMapping(mapTo = "sqrt") - protected float sqrt(float _f) { - return (float) Math.sqrt(_f); - } - - /** - * Delegates to either {@link java.lang.Math#sqrt(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#sqrt(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(double)</a></code> - * @return {@link java.lang.Math#sqrt(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(double)</a></code> - * - * @see java.lang.Math#sqrt(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(double)</a></code> - */ - @OpenCLMapping(mapTo = "sqrt") - protected double sqrt(double _d) { - return Math.sqrt(_d); - } - - /** - * Delegates to either {@link java.lang.Math#tan(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(float)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#tan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(float)</a></code> - * @return {@link java.lang.Math#tan(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(float)</a></code> - * - * @see java.lang.Math#tan(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(float)</a></code> - */ - @OpenCLMapping(mapTo = "tan") - protected float tan(float _f) { - return (float) Math.tan(_f); - } - - /** - * Delegates to either {@link java.lang.Math#tan(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#tan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(double)</a></code> - * @return {@link java.lang.Math#tan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(double)</a></code> - * - * @see java.lang.Math#tan(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(double)</a></code> - */ - @OpenCLMapping(mapTo = "tan") - protected double tan(double _d) { - return Math.tan(_d); - } - - // the following rsqrt and native_sqrt and native_rsqrt don't exist in java Math - // but added them here for nbody testing, not sure if we want to expose them - /** - * Computes inverse square root using {@link java.lang.Math#sqrt(double)} (Java) or delegates to <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _f value to delegate to {@link java.lang.Math#sqrt(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> - * @return <code>( 1.0f / {@link java.lang.Math#sqrt(double)} casted to float )</code>/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> - * - * @see java.lang.Math#sqrt(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> - */ - @OpenCLMapping(mapTo = "rsqrt") - protected float rsqrt(float _f) { - return (1.0f / (float) Math.sqrt(_f)); - } - - /** - * Computes inverse square root using {@link java.lang.Math#sqrt(double)} (Java) or delegates to <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> (OpenCL). - * - * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. - * - * @param _d value to delegate to {@link java.lang.Math#sqrt(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> - * @return <code>( 1.0f / {@link java.lang.Math#sqrt(double)} )</code> /<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> - * - * @see java.lang.Math#sqrt(double) - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> - */ - @OpenCLMapping(mapTo = "rsqrt") - protected double rsqrt(double _d) { - return (1.0 / Math.sqrt(_d)); - } - - @OpenCLMapping(mapTo = "native_sqrt") - private float native_sqrt(float _f) { - int j = Float.floatToIntBits(_f); - j = ((1 << 29) + (j >> 1)) - (1 << 22) - 0x4c00; - return (Float.intBitsToFloat(j)); - // could add more precision using one iteration of newton's method, use the following - } - - @OpenCLMapping(mapTo = "native_rsqrt") - private float native_rsqrt(float _f) { - int j = Float.floatToIntBits(_f); - j = 0x5f3759df - (j >> 1); - final float x = (Float.intBitsToFloat(j)); - return x; - // if want more precision via one iteration of newton's method, use the following - // float fhalf = 0.5f*_f; - // return (x *(1.5f - fhalf * x * x)); - } - - // Hacked from AtomicIntegerArray.getAndAdd(i, delta) - /** - * Atomically adds <code>_delta</code> value to <code>_index</code> element of array <code>_arr</code> (Java) or delegates to <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atomic_add.html">atomic_add(volatile int*, int)</a></code> (OpenCL). - * - * - * @param _arr array for which an element value needs to be atomically incremented by <code>_delta</code> - * @param _index index of the <code>_arr</code> array that needs to be atomically incremented by <code>_delta</code> - * @param _delta value by which <code>_index</code> element of <code>_arr</code> array needs to be atomically incremented - * @return previous value of <code>_index</code> element of <code>_arr</code> array - * - * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atomic_add.html">atomic_add(volatile int*, int)</a></code> - */ - @OpenCLMapping(atomic32 = true) - protected int atomicAdd(int[] _arr, int _index, int _delta) { - if (!Config.disableUnsafe) { - return UnsafeWrapper.atomicAdd(_arr, _index, _delta); - } else { - synchronized (_arr) { - final int previous = _arr[_index]; - _arr[_index] += _delta; - return previous; - } - } - } - - /** - * Wait for all kernels in the current group to rendezvous at this call before continuing execution. - * - * @annotion Experimental - */ - @OpenCLDelegate - @Experimental - protected final void localBarrier() { - kernelState.awaitOnLocalBarrier(); - } - - /** - * Wait for all kernels in the current group to rendezvous at this call before continuing execution. - * - * - * Java version is identical to localBarrier() - * - * @annotion Experimental - * @deprecated - */ - @OpenCLDelegate - @Experimental - @Deprecated - protected final void globalBarrier() throws DeprecatedException { - throw new DeprecatedException( - "Kernel.globalBarrier() has been deprecated. It was based an incorrect understanding of OpenCL functionality."); - } - - @OpenCLMapping(mapTo = "hypot") - protected float hypot(final float a, final float b) { - return (float) Math.hypot(a, b); - } - - @OpenCLMapping(mapTo = "hypot") - protected double hypot(final double a, final double b) { - return Math.hypot(a, b); - } - - public KernelState getKernelState() { - return kernelState; - } - - private KernelRunner prepareKernelRunner() { - if (kernelRunner == null) { - kernelRunner = new KernelRunner(this); - } - return kernelRunner; - } - - /** - * Determine the execution time of the previous Kernel.execute(range) call. - * - * Note that for the first call this will include the conversion time. - * - * @return The time spent executing the kernel (ms) - * - * @see #getConversionTime(); - * @see #getAccumulatedExecutionTime(); - * - */ - public double getExecutionTime() { - KernelProfile profile = KernelManager.instance().getProfile(getClass()); - synchronized (profile) { - return profile.getLastExecutionTime(); - } - } - - /** - * Determine the total execution time of all previous Kernel.execute(range) calls. - * - * Note that this will include the initial conversion time. - * - * @return The total time spent executing the kernel (ms) - * - * @see #getExecutionTime(); - * @see #getConversionTime(); - * - */ - public double getAccumulatedExecutionTime() { - KernelProfile profile = KernelManager.instance().getProfile(getClass()); - synchronized (profile) { - return profile.getAccumulatedTotalTime(); - } - } - - /** - * Determine the time taken to convert bytecode to OpenCL for first Kernel.execute(range) call. - * @return The time spent preparing the kernel for execution using GPU - * - * @see #getExecutionTime(); - * @see #getAccumulatedExecutionTime(); - */ - public double getConversionTime() { - KernelProfile profile = KernelManager.instance().getProfile(getClass()); - synchronized (profile) { - return profile.getLastConversionTime(); - } - } - - /** - * Start execution of <code>_range</code> kernels. - * <p> - * When <code>kernel.execute(globalSize)</code> is invoked, Aparapi will schedule the execution of <code>globalSize</code> kernels. If the execution mode is GPU then - * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. - * <p> - * @param _range The number of Kernels that we would like to initiate. - * @returnThe Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) - * - */ - public synchronized Kernel execute(Range _range) { - return (execute(_range, 1)); - } - - @Override - @SuppressWarnings("deprecation") - public String toString() { - if (executionMode == EXECUTION_MODE.AUTO) { - List<Device> preferredDevices = KernelManager.instance().getPreferences(this).getPreferredDevices(this); - StringBuilder preferredDevicesSummary = new StringBuilder("{"); - for (int i = 0; i < preferredDevices.size(); ++i) { - Device device = preferredDevices.get(i); - preferredDevicesSummary.append(device.getShortDescription()); - if (i < preferredDevices.size() - 1) { - preferredDevicesSummary.append("|"); - } - } - preferredDevicesSummary.append("}"); - return Reflection.getSimpleName(getClass()) + ", devices=" + preferredDevicesSummary.toString(); - } else { - return Reflection.getSimpleName(getClass()) + ", modes=" + executionModes + ", current = " + executionMode; - } - } - - /** - * Start execution of <code>_range</code> kernels. - * <p> - * When <code>kernel.execute(_range)</code> is 1invoked, Aparapi will schedule the execution of <code>_range</code> kernels. If the execution mode is GPU then - * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. - * <p> - * Since adding the new <code>Range class</code> this method offers backward compatibility and merely defers to <code> return (execute(Range.create(_range), 1));</code>. - * @param _range The number of Kernels that we would like to initiate. - * @returnThe Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) - * - */ - public synchronized Kernel execute(int _range) { - return (execute(createRange(_range), 1)); - } - - @SuppressWarnings("deprecation") - protected Range createRange(int _range) { - if (executionMode.equals(EXECUTION_MODE.AUTO)) { - Device device = getTargetDevice(); - Range range = Range.create(device, _range); - return range; - } else { - return Range.create(null, _range); - } - } - - /** - * Start execution of <code>_passes</code> iterations of <code>_range</code> kernels. - * <p> - * When <code>kernel.execute(_range, _passes)</code> is invoked, Aparapi will schedule the execution of <code>_reange</code> kernels. If the execution mode is GPU then - * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. - * <p> - * @param _passes The number of passes to make - * @return The Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) - * - */ - public synchronized Kernel execute(Range _range, int _passes) { - return (execute("run", _range, _passes)); - } - - /** - * Start execution of <code>_passes</code> iterations over the <code>_range</code> of kernels. - * <p> - * When <code>kernel.execute(_range)</code> is invoked, Aparapi will schedule the execution of <code>_range</code> kernels. If the execution mode is GPU then - * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. - * <p> - * Since adding the new <code>Range class</code> this method offers backward compatibility and merely defers to <code> return (execute(Range.create(_range), 1));</code>. - * @param _range The number of Kernels that we would like to initiate. - * @returnThe Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) - * - */ - public synchronized Kernel execute(int _range, int _passes) { - return (execute(createRange(_range), _passes)); - } - - /** - * Start execution of <code>globalSize</code> kernels for the given entrypoint. - * <p> - * When <code>kernel.execute("entrypoint", globalSize)</code> is invoked, Aparapi will schedule the execution of <code>globalSize</code> kernels. If the execution mode is GPU then - * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. - * <p> - * @param _entrypoint is the name of the method we wish to use as the entrypoint to the kernel - * @return The Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) - * - */ - public synchronized Kernel execute(String _entrypoint, Range _range) { - return (execute(_entrypoint, _range, 1)); - } - - /** - * Start execution of <code>globalSize</code> kernels for the given entrypoint. - * <p> - * When <code>kernel.execute("entrypoint", globalSize)</code> is invoked, Aparapi will schedule the execution of <code>globalSize</code> kernels. If the execution mode is GPU then - * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. - * <p> - * @param _entrypoint is the name of the method we wish to use as the entrypoint to the kernel - * @return The Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) - * - */ - public synchronized Kernel execute(String _entrypoint, Range _range, int _passes) { - return prepareKernelRunner().execute(_entrypoint, _range, _passes); - } - - public boolean isAutoCleanUpArrays() { - return autoCleanUpArrays; - } - - /** - * Property which if true enables automatic calling of {@link #cleanUpArrays()} following each execution. - */ - public void setAutoCleanUpArrays(boolean autoCleanUpArrays) { - this.autoCleanUpArrays = autoCleanUpArrays; - } - - /** - * Frees the bulk of the resources used by this kernel, by setting array sizes in non-primitive {@link KernelArg}s to 1 (0 size is prohibited) and invoking kernel - * execution on a zero size range. Unlike {@link #dispose()}, this does not prohibit further invocations of this kernel, as sundry resources such as OpenCL queues are - * <b>not</b> freed by this method. - * - * <p>This allows a "dormant" Kernel to remain in existence without undue strain on GPU resources, which may be strongly preferable to disposing a Kernel and - * recreating another one later, as creation/use of a new Kernel (specifically creation of its associated OpenCL context) is expensive.</p> - * - * <p>Note that where the underlying array field is declared final, for obvious reasons it is not resized to zero.</p> - */ - public synchronized void cleanUpArrays() { - if (kernelRunner != null) { - kernelRunner.cleanUpArrays(); - } - } - - /** - * Release any resources associated with this Kernel. - * <p> - * When the execution mode is <code>CPU</code> or <code>GPU</code>, Aparapi stores some OpenCL resources in a data structure associated with the kernel instance. The - * <code>dispose()</code> method must be called to release these resources. - * <p> - * If <code>execute(int _globalSize)</code> is called after <code>dispose()</code> is called the results are undefined. - */ - public synchronized void dispose() { - if (kernelRunner != null) { - kernelRunner.dispose(); - kernelRunner = null; - } - } - - public boolean isRunningCL() { - return getTargetDevice() instanceof OpenCLDevice; - } - - public final Device getTargetDevice() { - return KernelManager.instance().getPreferences(this).getPreferredDevice(this); - } - - /** @return true by default, may be overriden to allow vetoing of a device or devices by a given Kernel instance. */ - public boolean isAllowDevice(Device _device) { - return true; - } - - /** - * @deprecated See {@link EXECUTION_MODE} - * <p> - * Return the current execution mode. - * - * Before a Kernel executes, this return value will be the execution mode as determined by the setting of - * the EXECUTION_MODE enumeration. By default, this setting is either <b>GPU</b> - * if OpenCL is available on the target system, or <b>JTP</b> otherwise. This default setting can be - * changed by calling setExecutionMode(). - * - * <p> - * After a Kernel executes, the return value will be the mode in which the Kernel actually executed. - * - * @return The current execution mode. - * - * @see #setExecutionMode(EXECUTION_MODE) - */ - @Deprecated - public EXECUTION_MODE getExecutionMode() { - return (executionMode); - } - - /** - * @deprecated See {@link EXECUTION_MODE} - * <p> - * Set the execution mode. - * <p> - * This should be regarded as a request. The real mode will be determined at runtime based on the availability of OpenCL and the characteristics of the workload. - * - * @param _executionMode the requested execution mode. - * - * @see #getExecutionMode() - */ - @Deprecated - public void setExecutionMode(EXECUTION_MODE _executionMode) { - executionMode = _executionMode; - } - - public void setExecutionModeWithoutFallback(EXECUTION_MODE _executionMode) { - executionModes.clear(); - executionModes.add(_executionMode); - currentMode = executionModes.iterator(); - executionMode = currentMode.next(); } - - /** - * @deprecated See {@link EXECUTION_MODE} - */ - @Deprecated - public void setFallbackExecutionMode() { - executionMode = EXECUTION_MODE.getFallbackExecutionMode(); - } - - final static Map<String, String> typeToLetterMap = new HashMap<String, String>(); - - static { - // only primitive types for now - typeToLetterMap.put("double", "D"); - typeToLetterMap.put("float", "F"); - typeToLetterMap.put("int", "I"); - typeToLetterMap.put("long", "J"); - typeToLetterMap.put("boolean", "Z"); - typeToLetterMap.put("byte", "B"); - typeToLetterMap.put("char", "C"); - typeToLetterMap.put("short", "S"); - typeToLetterMap.put("void", "V"); - } - - private static String descriptorToReturnTypeLetter(String desc) { - // find the letter after the closed parenthesis - return desc.substring(desc.lastIndexOf(')') + 1); - } - - private static String getReturnTypeLetter(Method meth) { - return toClassShortNameIfAny(meth.getReturnType()); - } - - private static String toClassShortNameIfAny(final Class<?> retClass) { - if (retClass.isArray()) { - return "[" + toClassShortNameIfAny(retClass.getComponentType()); - } - final String strRetClass = retClass.toString(); - final String mapping = typeToLetterMap.get(strRetClass); - // System.out.println("strRetClass = <" + strRetClass + ">, mapping = " + mapping); - if (mapping == null) - return "[" + retClass.getName() + ";"; - return mapping; - } - - public static String getMappedMethodName(MethodReferenceEntry _methodReferenceEntry) { - if (CacheEnabler.areCachesEnabled()) - return getProperty(mappedMethodNamesCache, _methodReferenceEntry, null); - String mappedName = null; - final String name = _methodReferenceEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - Class<?> currentClass = _methodReferenceEntry.getOwnerClassModel().getClassWeAreModelling(); - while (currentClass != Object.class) { - for (final Method kernelMethod : currentClass.getDeclaredMethods()) { - if (kernelMethod.isAnnotationPresent(OpenCLMapping.class)) { - // ultimately, need a way to constrain this based upon signature (to disambiguate abs(float) from abs(int); - // for Alpha, we will just disambiguate based on the return type - if (false) { - System.out.println("kernelMethod is ... " + kernelMethod.toGenericString()); - System.out.println("returnType = " + kernelMethod.getReturnType()); - System.out.println("returnTypeLetter = " + getReturnTypeLetter(kernelMethod)); - System.out.println("kernelMethod getName = " + kernelMethod.getName()); - System.out.println("methRefName = " + name + " descriptor = " - + _methodReferenceEntry.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8()); - System.out.println("descToReturnTypeLetter = " - + descriptorToReturnTypeLetter(_methodReferenceEntry.getNameAndTypeEntry().getDescriptorUTF8Entry() - .getUTF8())); - } - if (toSignature(_methodReferenceEntry).equals(toSignature(kernelMethod))) { - final OpenCLMapping annotation = kernelMethod.getAnnotation(OpenCLMapping.class); - final String mapTo = annotation.mapTo(); - if (!mapTo.equals("")) { - mappedName = mapTo; - // System.out.println("mapTo = " + mapTo); - } - } - } - } - if (mappedName != null) - break; - currentClass = currentClass.getSuperclass(); - } - // System.out.println("... in getMappedMethodName, returning = " + mappedName); - return (mappedName); - } - - public static boolean isMappedMethod(MethodReferenceEntry methodReferenceEntry) { - if (CacheEnabler.areCachesEnabled()) - return getBoolean(mappedMethodFlags, methodReferenceEntry); - boolean isMapped = false; - for (final Method kernelMethod : Kernel.class.getDeclaredMethods()) { - if (kernelMethod.isAnnotationPresent(OpenCLMapping.class)) { - if (methodReferenceEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(kernelMethod.getName())) { - - // well they have the same name ;) - isMapped = true; - } - } - } - return (isMapped); - } - - public static boolean isOpenCLDelegateMethod(MethodReferenceEntry methodReferenceEntry) { - if (CacheEnabler.areCachesEnabled()) - return getBoolean(openCLDelegateMethodFlags, methodReferenceEntry); - boolean isMapped = false; - for (final Method kernelMethod : Kernel.class.getDeclaredMethods()) { - if (kernelMethod.isAnnotationPresent(OpenCLDelegate.class)) { - if (methodReferenceEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(kernelMethod.getName())) { - - // well they have the same name ;) - isMapped = true; - } - } - } - return (isMapped); - } - - public static boolean usesAtomic32(MethodReferenceEntry methodReferenceEntry) { - if (CacheEnabler.areCachesEnabled()) - return getProperty(atomic32Cache, methodReferenceEntry, false); - for (final Method kernelMethod : Kernel.class.getDeclaredMethods()) { - if (kernelMethod.isAnnotationPresent(OpenCLMapping.class)) { - if (methodReferenceEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(kernelMethod.getName())) { - final OpenCLMapping annotation = kernelMethod.getAnnotation(OpenCLMapping.class); - return annotation.atomic32(); - } - } - } - return (false); - } - - // For alpha release atomic64 is not supported - public static boolean usesAtomic64(MethodReferenceEntry methodReferenceEntry) { - // if (CacheEnabler.areCachesEnabled()) - // return getProperty(atomic64Cache, methodReferenceEntry, false); - //for (java.lang.reflect.Method kernelMethod : Kernel.class.getDeclaredMethods()) { - // if (kernelMethod.isAnnotationPresent(Kernel.OpenCLMapping.class)) { - // if (methodReferenceEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(kernelMethod.getName())) { - // OpenCLMapping annotation = kernelMethod.getAnnotation(Kernel.OpenCLMapping.class); - // return annotation.atomic64(); - // } - // } - //} - return (false); - } - - // the flag useNullForLocalSize is useful for testing that what we compute for localSize is what OpenCL - // would also compute if we passed in null. In non-testing mode, we just call execute with the - // same localSize that we computed in getLocalSizeJNI. We don't want do publicize these of course. - // GRF we can't access this from test classes without exposing in in javadoc so I left the flag but made the test/set of the flag reflectively - boolean useNullForLocalSize = false; - - // Explicit memory management API's follow - - /** - * For dev purposes (we should remove this for production) allow us to define that this Kernel uses explicit memory management - * @param _explicit (true if we want explicit memory management) - */ - public void setExplicit(boolean _explicit) { - prepareKernelRunner().setExplicit(_explicit); - } - - /** - * For dev purposes (we should remove this for production) determine whether this Kernel uses explicit memory management - * @return (true if we kernel is using explicit memory management) - */ - public boolean isExplicit() { - return prepareKernelRunner().isExplicit(); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(long[] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(long[][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(long[][][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(double[] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(double[][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(double[][][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(float[] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(float[][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(float[][][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(int[] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(int[][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(int[][][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(byte[] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(byte[][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(byte[][][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(char[] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(char[][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(char[][][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(boolean[] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(boolean[][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel put(boolean[][][] array) { - prepareKernelRunner().put(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(long[] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(long[][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(long[][][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(double[] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(double[][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(double[][][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(float[] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(float[][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(float[][][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(int[] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(int[][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(int[][][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(byte[] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(byte[][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(byte[][][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(char[] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(char[][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(char[][][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(boolean[] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(boolean[][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. - * @param array - * @return This kernel so that we can use the 'fluent' style API - */ - public Kernel get(boolean[][][] array) { - prepareKernelRunner().get(array); - return (this); - } - - /** - * Get the profiling information from the last successful call to Kernel.execute(). - * @return A list of ProfileInfo records - */ - public List<ProfileInfo> getProfileInfo() { - return prepareKernelRunner().getProfileInfo(); - } - - /** - * @deprecated See {@link EXECUTION_MODE}. - */ - @Deprecated - private final LinkedHashSet<EXECUTION_MODE> executionModes = (Config.executionMode != null) ? EXECUTION_MODE.getDefaultExecutionModes() : new LinkedHashSet<>(Collections.singleton(EXECUTION_MODE.AUTO)); - - /** - * @deprecated See {@link EXECUTION_MODE}. - */ - @Deprecated - private Iterator<EXECUTION_MODE> currentMode = executionModes.iterator(); - - /** - * @deprecated See {@link EXECUTION_MODE}. - */ - @Deprecated - private EXECUTION_MODE executionMode = currentMode.next(); - - /** - * @deprecated See {@link EXECUTION_MODE}. - * <p> - * set possible fallback path for execution modes. - * for example setExecutionFallbackPath(GPU,CPU,JTP) will try to use the GPU - * if it fails it will fall back to OpenCL CPU and finally it will try JTP. - */ - @Deprecated - public void addExecutionModes(EXECUTION_MODE... platforms) { - executionModes.addAll(Arrays.asList(platforms)); - currentMode = executionModes.iterator(); - executionMode = currentMode.next(); - } - - /** - * @deprecated See {@link EXECUTION_MODE}. - * @return is there another execution path we can try - */ - @Deprecated - public boolean hasNextExecutionMode() { - return currentMode.hasNext(); - } - - /** - * @deprecated See {@link EXECUTION_MODE}. - * try the next execution path in the list if there aren't any more than give up - */ - @Deprecated - public void tryNextExecutionMode() { - if (currentMode.hasNext()) { - executionMode = currentMode.next(); - } - } - - private static final ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> mappedMethodFlags = markedWith(OpenCLMapping.class); - - private static final ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> openCLDelegateMethodFlags = markedWith(OpenCLDelegate.class); - - private static final ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> atomic32Cache = cacheProperty(new ValueComputer<Class<?>, Map<String, Boolean>>() { - @Override - public Map<String, Boolean> compute(Class<?> key) { - Map<String, Boolean> properties = new HashMap<>(); - for (final Method method : key.getDeclaredMethods()) { - if (isRelevant(method) && method.isAnnotationPresent(OpenCLMapping.class)) { - properties.put(toSignature(method), method.getAnnotation(OpenCLMapping.class).atomic32()); - } - } - return properties; - } - }); - - private static final ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> atomic64Cache = cacheProperty(new ValueComputer<Class<?>, Map<String, Boolean>>() { - @Override - public Map<String, Boolean> compute(Class<?> key) { - Map<String, Boolean> properties = new HashMap<>(); - for (final Method method : key.getDeclaredMethods()) { - if (isRelevant(method) && method.isAnnotationPresent(OpenCLMapping.class)) { - properties.put(toSignature(method), method.getAnnotation(OpenCLMapping.class).atomic64()); - } - } - return properties; - } - }); - - private static boolean getBoolean(ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> methodNamesCache, - MethodReferenceEntry methodReferenceEntry) { - return getProperty(methodNamesCache, methodReferenceEntry, false); - } - - private static <A extends Annotation> ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> markedWith( - final Class<A> annotationClass) { - return cacheProperty(new ValueComputer<Class<?>, Map<String, Boolean>>() { - @Override - public Map<String, Boolean> compute(Class<?> key) { - Map<String, Boolean> markedMethodNames = new HashMap<>(); - for (final Method method : key.getDeclaredMethods()) { - markedMethodNames.put(toSignature(method), method.isAnnotationPresent(annotationClass)); - } - return markedMethodNames; - } - }); - } - - static String toSignature(Method method) { - return method.getName() + getArgumentsLetters(method) + getReturnTypeLetter(method); - } - - private static String getArgumentsLetters(Method method) { - StringBuilder sb = new StringBuilder("("); - for (Class<?> parameterClass : method.getParameterTypes()) { - sb.append(toClassShortNameIfAny(parameterClass)); - } - sb.append(")"); - return sb.toString(); - } - - private static boolean isRelevant(Method method) { - return !method.isSynthetic() && !method.isBridge(); - } - - private static <V, T extends Throwable> V getProperty(ValueCache<Class<?>, Map<String, V>, T> cache, - MethodReferenceEntry methodReferenceEntry, V defaultValue) throws T { - Map<String, V> map = cache.computeIfAbsent(methodReferenceEntry.getOwnerClassModel().getClassWeAreModelling()); - String key = toSignature(methodReferenceEntry); - if (map.containsKey(key)) - return map.get(key); - return defaultValue; - } - - private static String toSignature(MethodReferenceEntry methodReferenceEntry) { - NameAndTypeEntry nameAndTypeEntry = methodReferenceEntry.getNameAndTypeEntry(); - return nameAndTypeEntry.getNameUTF8Entry().getUTF8() + nameAndTypeEntry.getDescriptorUTF8Entry().getUTF8(); - } - - private static final ValueCache<Class<?>, Map<String, String>, RuntimeException> mappedMethodNamesCache = cacheProperty(new ValueComputer<Class<?>, Map<String, String>>() { - @Override - public Map<String, String> compute(Class<?> key) { - Map<String, String> properties = new HashMap<>(); - for (final Method method : key.getDeclaredMethods()) { - if (isRelevant(method) && method.isAnnotationPresent(OpenCLMapping.class)) { - // ultimately, need a way to constrain this based upon signature (to disambiguate abs(float) from abs(int); - final OpenCLMapping annotation = method.getAnnotation(OpenCLMapping.class); - final String mapTo = annotation.mapTo(); - if (mapTo != null && !mapTo.equals("")) { - properties.put(toSignature(method), mapTo); - } - } - } - return properties; - } - }); - - private static <K, V, T extends Throwable> ValueCache<Class<?>, Map<K, V>, T> cacheProperty( - final ThrowingValueComputer<Class<?>, Map<K, V>, T> throwingValueComputer) { - return ValueCache.on(new ThrowingValueComputer<Class<?>, Map<K, V>, T>() { - @Override - public Map<K, V> compute(Class<?> key) throws T { - Map<K, V> properties = new HashMap<>(); - Deque<Class<?>> superclasses = new ArrayDeque<>(); - Class<?> currentSuperClass = key; - do { - superclasses.push(currentSuperClass); - currentSuperClass = currentSuperClass.getSuperclass(); - } while (currentSuperClass != Object.class); - for (Class<?> clazz : superclasses) { - // Overwrite property values for shadowed/overriden methods - properties.putAll(throwingValueComputer.compute(clazz)); - } - return properties; - } - }); - } - - public static void invalidateCaches() { - atomic32Cache.invalidate(); - atomic64Cache.invalidate(); - mappedMethodFlags.invalidate(); - mappedMethodNamesCache.invalidate(); - openCLDelegateMethodFlags.invalidate(); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi; + +import com.aparapi.annotation.Experimental; +import com.aparapi.exception.DeprecatedException; +import com.aparapi.internal.model.CacheEnabler; +import com.aparapi.internal.model.ClassModel.ConstantPool.MethodReferenceEntry; +import com.aparapi.internal.model.ClassModel.ConstantPool.NameAndTypeEntry; +import com.aparapi.internal.model.ValueCache; +import com.aparapi.internal.model.ValueCache.ThrowingValueComputer; +import com.aparapi.internal.model.ValueCache.ValueComputer; +import com.aparapi.internal.opencl.OpenCLLoader; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.logging.Logger; + +import com.aparapi.device.Device; +import com.aparapi.device.JavaDevice; +import com.aparapi.device.OpenCLDevice; +import com.aparapi.internal.kernel.KernelArg; +import com.aparapi.internal.kernel.KernelManager; +import com.aparapi.internal.kernel.KernelProfile; +import com.aparapi.internal.kernel.KernelRunner; +import com.aparapi.internal.util.Reflection; +import com.aparapi.internal.util.UnsafeWrapper; + +/** + * A <i>kernel</i> encapsulates a data parallel algorithm that will execute either on a GPU + * (through conversion to OpenCL) or on a CPU via a Java Thread Pool. + * <p> + * To write a new kernel, a developer extends the <code>Kernel</code> class and overrides the <code>Kernel.run()</code> method. + * To execute this kernel, the developer creates a new instance of it and calls <code>Kernel.execute(int globalSize)</code> with a suitable 'global size'. At runtime + * Aparapi will attempt to convert the <code>Kernel.run()</code> method (and any method called directly or indirectly + * by <code>Kernel.run()</code>) into OpenCL for execution on GPU devices made available via the OpenCL platform. + * <p> + * Note that <code>Kernel.run()</code> is not called directly. Instead, + * the <code>Kernel.execute(int globalSize)</code> method will cause the overridden <code>Kernel.run()</code> + * method to be invoked once for each value in the range <code>0...globalSize</code>. + * <p> + * On the first call to <code>Kernel.execute(int _globalSize)</code>, Aparapi will determine the EXECUTION_MODE of the kernel. + * This decision is made dynamically based on two factors: + * <ol> + * <li>Whether OpenCL is available (appropriate drivers are installed and the OpenCL and Aparapi dynamic libraries are included on the system path).</li> + * <li>Whether the bytecode of the <code>run()</code> method (and every method that can be called directly or indirectly from the <code>run()</code> method) + * can be converted into OpenCL.</li> + * </ol> + * <p> + * Below is an example Kernel that calculates the square of a set of input values. + * <p> + * <blockquote><pre> + * class SquareKernel extends Kernel{ + * private int values[]; + * private int squares[]; + * public SquareKernel(int values[]){ + * this.values = values; + * squares = new int[values.length]; + * } + * public void run() { + * int gid = getGlobalID(); + * squares[gid] = values[gid]*values[gid]; + * } + * public int[] getSquares(){ + * return(squares); + * } + * } + * </pre></blockquote> + * <p> + * To execute this kernel, first create a new instance of it and then call <code>execute(Range _range)</code>. + * <p> + * <blockquote><pre> + * int[] values = new int[1024]; + * // fill values array + * Range range = Range.create(values.length); // create a range 0..1024 + * SquareKernel kernel = new SquareKernel(values); + * kernel.execute(range); + * </pre></blockquote> + * <p> + * When <code>execute(Range)</code> returns, all the executions of <code>Kernel.run()</code> have completed and the results are available in the <code>squares</code> array. + * <p> + * <blockquote><pre> + * int[] squares = kernel.getSquares(); + * for (int i=0; i< values.length; i++){ + * System.out.printf("%4d %4d %8d\n", i, values[i], squares[i]); + * } + * </pre></blockquote> + * <p> + * A different approach to creating kernels that avoids extending Kernel is to write an anonymous inner class: + * <p> + * <blockquote><pre> + * + * final int[] values = new int[1024]; + * // fill the values array + * final int[] squares = new int[values.length]; + * final Range range = Range.create(values.length); + * + * Kernel kernel = new Kernel(){ + * public void run() { + * int gid = getGlobalID(); + * squares[gid] = values[gid]*values[gid]; + * } + * }; + * kernel.execute(range); + * for (int i=0; i< values.length; i++){ + * System.out.printf("%4d %4d %8d\n", i, values[i], squares[i]); + * } + * + * </pre></blockquote> + * <p> + * + * @author gfrost AMD Javalabs + * @version Alpha, 21/09/2010 + */ +public abstract class Kernel implements Cloneable { + + private static Logger logger = Logger.getLogger(Config.getLoggerName()); + + /** + * We can use this Annotation to 'tag' intended local buffers. + * + * So we can either annotate the buffer + * <pre><code> + * @Local int[] buffer = new int[1024]; + * </code></pre> + * Or use a special suffix + * <pre><code> + * int[] buffer_$local$ = new int[1024]; + * </code></pre> + * + * @see #LOCAL_SUFFIX + * + * + */ + @Retention(RetentionPolicy.RUNTIME) + public @interface Local { + + } + + /** + * We can use this Annotation to 'tag' intended constant buffers. + * + * So we can either annotate the buffer + * <pre><code> + * @Constant int[] buffer = new int[1024]; + * </code></pre> + * Or use a special suffix + * <pre><code> + * int[] buffer_$constant$ = new int[1024]; + * </code></pre> + * + * @see #LOCAL_SUFFIX + * + * + */ + @Retention(RetentionPolicy.RUNTIME) + public @interface Constant { + + } + + /** + * + * We can use this Annotation to 'tag' __private (unshared) array fields. Data in the __private address space in OpenCL is accessible only from + * the current kernel instance. + * + * To so mark a field with a buffer size of 99, we can either annotate the buffer + * <pre><code> + * @PrivateMemorySpace(99) int[] buffer = new int[99]; + * </code></pre> + * Or use a special suffix + * <pre><code> + * int[] buffer_$private$99 = new int[99]; + * </code></pre> + * + * <p>Note that any code which must be runnable in {@link EXECUTION_MODE#JTP} will fail to work correctly if it uses such an + * array, as the array will be shared by all threads. The solution is to create a {@link NoCL} method called at the start of {@link #run()} which sets + * the field to an array returned from a static <code>ThreadLocal<foo[]></code></p>. Please see <code>MedianKernel7x7</code> in the samples for an example. + * + * @see #PRIVATE_SUFFIX + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD}) + public @interface PrivateMemorySpace { + /** Size of the array used as __private buffer. */ + int value(); + } + + /** + * Annotation which can be applied to either a getter (with usual java bean naming convention relative to an instance field), or to any method + * with void return type, which prevents both the method body and any calls to the method being emitted in the generated OpenCL. (In the case of a getter, the + * underlying field is used in place of the NoCL getter method.) This allows for code specialization within a java/JTP execution path, for example to + * allow logging/breakpointing when debugging, or to apply ThreadLocal processing (see {@link PrivateMemorySpace}) in java to simulate OpenCL __private + * memory. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.FIELD}) + public @interface NoCL { + // empty + } + + /** + * We can use this suffix to 'tag' intended local buffers. + * + * + * So either name the buffer + * <pre><code> + * int[] buffer_$local$ = new int[1024]; + * </code></pre> + * Or use the Annotation form + * <pre><code> + * @Local int[] buffer = new int[1024]; + * </code></pre> + */ + public final static String LOCAL_SUFFIX = "_$local$"; + + /** + * We can use this suffix to 'tag' intended constant buffers. + * + * + * So either name the buffer + * <pre><code> + * int[] buffer_$constant$ = new int[1024]; + * </code></pre> + * Or use the Annotation form + * <pre><code> + * @Constant int[] buffer = new int[1024]; + * </code></pre> + */ + public final static String CONSTANT_SUFFIX = "_$constant$"; + + /** + * We can use this suffix to 'tag' __private buffers. + * + * <p>So either name the buffer + * <pre><code> + * int[] buffer_$private$32 = new int[32]; + * </code></pre> + * Or use the Annotation form + * <pre><code> + * @PrivateMemorySpace(32) int[] buffer = new int[32]; + * </code></pre> + * + * @see PrivateMemorySpace for a more detailed usage summary + */ + public final static String PRIVATE_SUFFIX = "_$private$"; + + /** + * This annotation is for internal use only + */ + @Retention(RetentionPolicy.RUNTIME) + protected @interface OpenCLDelegate { + + } + + /** + * This annotation is for internal use only + */ + @Retention(RetentionPolicy.RUNTIME) + protected @interface OpenCLMapping { + String mapTo() default ""; + + boolean atomic32() default false; + + boolean atomic64() default false; + } + + public abstract class Entry { + public abstract void run(); + + public Kernel execute(Range _range) { + return (Kernel.this.execute("foo", _range, 1)); + } + } + + /** + * @deprecated It is no longer recommended that {@code EXECUTION_MODE}s are used, as a more sophisticated {@link com.aparapi.device.Device} + * preference mechanism is in place, see {@link com.aparapi.internal.kernel.KernelManager}. Though {@link #setExecutionMode(EXECUTION_MODE)} + * is still honored, the default EXECUTION_MODE is now {@link EXECUTION_MODE#AUTO}, which indicates that the KernelManager + * will determine execution behaviours. + * + * <p> + * The <i>execution mode</i> ENUM enumerates the possible modes of executing a kernel. + * One can request a mode of execution using the values below, and query a kernel after it first executes to + * determine how it executed. + * + * <p> + * Aparapi supports 5 execution modes. Default is GPU. + * <ul> + * <table> + * <tr><th align="left">Enum value</th><th align="left">Execution</th></tr> + * <tr><td><code><b>GPU</b></code></td><td>Execute using OpenCL on first available GPU device</td></tr> + * <tr><td><code><b>ACC</b></code></td><td>Execute using OpenCL on first available Accelerator device</td></tr> + * <tr><td><code><b>CPU</b></code></td><td>Execute using OpenCL on first available CPU device</td></tr> + * <tr><td><code><b>JTP</b></code></td><td>Execute using a Java Thread Pool (one thread spawned per available core)</td></tr> + * <tr><td><code><b>SEQ</b></code></td><td>Execute using a single loop. This is useful for debugging but will be less + * performant than the other modes</td></tr> + * </table> + * </ul> + * <p> + * To request that a kernel is executed in a specific mode, call <code>Kernel.setExecutionMode(EXECUTION_MODE)</code> before the + * kernel first executes. + * <p> + * <blockquote><pre> + * int[] values = new int[1024]; + * // fill values array + * SquareKernel kernel = new SquareKernel(values); + * kernel.setExecutionMode(Kernel.EXECUTION_MODE.JTP); + * kernel.execute(values.length); + * </pre></blockquote> + * <p> +<<<<<<< HEAD:src/main/java/com/aparapi/Kernel.java + * Alternatively, the property <code>com.aparapi.executionMode</code> can be set to one of <code>JTP,GPU,ACC,CPU,SEQ</code> + * when an application is launched. + * <p><blockquote><pre> + * java -classpath ....;aparapi.jar -Dcom.aparapi.executionMode=GPU MyApplication +======= + * Alternatively, the property <code>com.amd.aparapi.executionMode</code> can be set to one of <code>JTP,GPU,ACC,CPU,SEQ</code> + * when an application is launched. + * <p><blockquote><pre> + * java -classpath ....;aparapi.jar -Dcom.amd.aparapi.executionMode=GPU MyApplication +>>>>>>> b118aad... added method to set execution mode without any fallback:com.amd.aparapi/src/java/com/amd/aparapi/Kernel.java + * </pre></blockquote><p> + * Generally setting the execution mode is not recommended (it is best to let Aparapi decide automatically) but the option + * provides a way to compare a kernel's performance under multiple execution modes. + * + * @author gfrost AMD Javalabs + * @version Alpha, 21/09/2010 + */ + @Deprecated + public static enum EXECUTION_MODE { + /** + * + */ + AUTO, + /** + * A dummy value to indicate an unknown state. + */ + NONE, + /** + * The value representing execution on a GPU device via OpenCL. + */ + GPU, + /** + * The value representing execution on a CPU device via OpenCL. + * <p> + * <b>Note</b> not all OpenCL implementations support OpenCL compute on the CPU. + */ + CPU, + /** + * The value representing execution on a Java Thread Pool. + * <p> + * By default one Java thread is started for each available core and each core will execute <code>globalSize/cores</code> work items. + * This creates a total of <code>globalSize%cores</code> threads to complete the work. + * Choose suitable values for <code>globalSize</code> to minimize the number of threads that are spawned. + */ + JTP, + /** + * The value representing execution sequentially in a single loop. + * <p> + * This is meant to be used for debugging a kernel. + */ + SEQ, + /** + * The value representing execution on an accelerator device (Xeon Phi) via OpenCL. + */ + ACC; + + /** + * @deprecated See {@link EXECUTION_MODE}. + */ + @Deprecated + static LinkedHashSet<EXECUTION_MODE> getDefaultExecutionModes() { + LinkedHashSet<EXECUTION_MODE> defaultExecutionModes = new LinkedHashSet<EXECUTION_MODE>(); + + if (OpenCLLoader.isOpenCLAvailable()) { + defaultExecutionModes.add(GPU); + defaultExecutionModes.add(JTP); + } else { + defaultExecutionModes.add(JTP); + } + + final String executionMode = Config.executionMode; + + if (executionMode != null) { + try { + LinkedHashSet<EXECUTION_MODE> requestedExecutionModes; + requestedExecutionModes = EXECUTION_MODE.getExecutionModeFromString(executionMode); + logger.fine("requested execution mode ="); + for (final EXECUTION_MODE mode : requestedExecutionModes) { + logger.fine(" " + mode); + } + if ((OpenCLLoader.isOpenCLAvailable() && EXECUTION_MODE.anyOpenCL(requestedExecutionModes)) + || !EXECUTION_MODE.anyOpenCL(requestedExecutionModes)) { + defaultExecutionModes = requestedExecutionModes; + } + } catch (final Throwable t) { + // we will take the default + } + } + + logger.info("default execution modes = " + defaultExecutionModes); + + for (final EXECUTION_MODE e : defaultExecutionModes) { + logger.info("SETTING DEFAULT MODE: " + e.toString()); + } + + return (defaultExecutionModes); + } + + static LinkedHashSet<EXECUTION_MODE> getExecutionModeFromString(String executionMode) { + final LinkedHashSet<EXECUTION_MODE> executionModes = new LinkedHashSet<EXECUTION_MODE>(); + for (final String mode : executionMode.split(",")) { + executionModes.add(valueOf(mode.toUpperCase())); + } + return executionModes; + } + + static EXECUTION_MODE getFallbackExecutionMode() { + final EXECUTION_MODE defaultFallbackExecutionMode = JTP; + logger.info("fallback execution mode = " + defaultFallbackExecutionMode); + return (defaultFallbackExecutionMode); + } + + static boolean anyOpenCL(LinkedHashSet<EXECUTION_MODE> _executionModes) { + for (final EXECUTION_MODE mode : _executionModes) { + if ((mode == GPU) || (mode == ACC) || (mode == CPU)) { + return true; + } + } + return false; + } + + public boolean isOpenCL() { + return (this == GPU) || (this == ACC) || (this == CPU); + } + }; + + private KernelRunner kernelRunner = null; + + private boolean autoCleanUpArrays = false; + + private KernelState kernelState = new KernelState(); + + /** + * This class is for internal Kernel state management<p> + * NOT INTENDED FOR USE BY USERS + */ + public final class KernelState { + + private int[] globalIds = new int[] {0, 0, 0}; + + private int[] localIds = new int[] {0, 0, 0}; + + private int[] groupIds = new int[] {0, 0, 0}; + + private Range range; + + private int passId; + + private volatile CyclicBarrier localBarrier; + + private boolean localBarrierDisabled; + + /** + * Default constructor + */ + protected KernelState() { + + } + + /** + * Copy constructor + */ + protected KernelState(KernelState kernelState) { + globalIds = kernelState.getGlobalIds(); + localIds = kernelState.getLocalIds(); + groupIds = kernelState.getGroupIds(); + range = kernelState.getRange(); + passId = kernelState.getPassId(); + localBarrier = kernelState.getLocalBarrier(); + } + + /** + * @return the globalIds + */ + public int[] getGlobalIds() { + return globalIds; + } + + /** + * @param globalIds the globalIds to set + */ + public void setGlobalIds(int[] globalIds) { + this.globalIds = globalIds; + } + + /** + * Set a specific index value + * + * @param _index + * @param value + */ + public void setGlobalId(int _index, int value) { + globalIds[_index] = value; + } + + /** + * @return the localIds + */ + public int[] getLocalIds() { + return localIds; + } + + /** + * @param localIds the localIds to set + */ + public void setLocalIds(int[] localIds) { + this.localIds = localIds; + } + + /** + * Set a specific index value + * + * @param _index + * @param value + */ + public void setLocalId(int _index, int value) { + localIds[_index] = value; + } + + /** + * @return the groupIds + */ + public int[] getGroupIds() { + return groupIds; + } + + /** + * @param groupIds the groupIds to set + */ + public void setGroupIds(int[] groupIds) { + this.groupIds = groupIds; + } + + /** + * Set a specific index value + * + * @param _index + * @param value + */ + public void setGroupId(int _index, int value) { + groupIds[_index] = value; + } + + /** + * @return the range + */ + public Range getRange() { + return range; + } + + /** + * @param range the range to set + */ + public void setRange(Range range) { + this.range = range; + } + + /** + * @return the passId + */ + public int getPassId() { + return passId; + } + + /** + * @param passId the passId to set + */ + public void setPassId(int passId) { + this.passId = passId; + } + + /** + * @return the localBarrier + */ + public CyclicBarrier getLocalBarrier() { + return localBarrier; + } + + /** + * @param localBarrier the localBarrier to set + */ + public void setLocalBarrier(CyclicBarrier localBarrier) { + this.localBarrier = localBarrier; + } + + public void awaitOnLocalBarrier() { + if (!localBarrierDisabled) { + try { + kernelState.getLocalBarrier().await(); + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final BrokenBarrierException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + public void disableLocalBarrier() { + localBarrierDisabled = true; + } + } + + /** + * Determine the globalId of an executing kernel. + * <p> + * The kernel implementation uses the globalId to determine which of the executing kernels (in the global domain space) this invocation is expected to deal with. + * <p> + * For example in a <code>SquareKernel</code> implementation: + * <p> + * <blockquote><pre> + * class SquareKernel extends Kernel{ + * private int values[]; + * private int squares[]; + * public SquareKernel(int values[]){ + * this.values = values; + * squares = new int[values.length]; + * } + * public void run() { + * int gid = getGlobalID(); + * squares[gid] = values[gid]*values[gid]; + * } + * public int[] getSquares(){ + * return(squares); + * } + * } + * </pre></blockquote> + * <p> + * Each invocation of <code>SquareKernel.run()</code> retrieves it's globalId by calling <code>getGlobalId()</code>, and then computes the value of <code>square[gid]</code> for a given value of <code>value[gid]</code>. + * <p> + * @return The globalId for the Kernel being executed + * + * @see #getLocalId() + * @see #getGroupId() + * @see #getGlobalSize() + * @see #getNumGroups() + * @see #getLocalSize() + */ + + @OpenCLDelegate + protected final int getGlobalId() { + return getGlobalId(0); + } + + @OpenCLDelegate + protected final int getGlobalId(int _dim) { + return kernelState.getGlobalIds()[_dim]; + } + + /* + @OpenCLDelegate protected final int getGlobalX() { + return (getGlobalId(0)); + } + + @OpenCLDelegate protected final int getGlobalY() { + return (getGlobalId(1)); + } + + @OpenCLDelegate protected final int getGlobalZ() { + return (getGlobalId(2)); + } + */ + /** + * Determine the groupId of an executing kernel. + * <p> + * When a <code>Kernel.execute(int globalSize)</code> is invoked for a particular kernel, the runtime will break the work into various 'groups'. + * <p> + * A kernel can use <code>getGroupId()</code> to determine which group a kernel is currently + * dispatched to + * <p> + * The following code would capture the groupId for each kernel and map it against globalId. + * <blockquote><pre> + * final int[] groupIds = new int[1024]; + * Kernel kernel = new Kernel(){ + * public void run() { + * int gid = getGlobalId(); + * groupIds[gid] = getGroupId(); + * } + * }; + * kernel.execute(groupIds.length); + * for (int i=0; i< values.length; i++){ + * System.out.printf("%4d %4d\n", i, groupIds[i]); + * } + * </pre></blockquote> + * + * @see #getLocalId() + * @see #getGlobalId() + * @see #getGlobalSize() + * @see #getNumGroups() + * @see #getLocalSize() + * + * @return The groupId for this Kernel being executed + */ + @OpenCLDelegate + protected final int getGroupId() { + return getGroupId(0); + } + + @OpenCLDelegate + protected final int getGroupId(int _dim) { + return kernelState.getGroupIds()[_dim]; + } + + /* + @OpenCLDelegate protected final int getGroupX() { + return (getGroupId(0)); + } + + @OpenCLDelegate protected final int getGroupY() { + return (getGroupId(1)); + } + + @OpenCLDelegate protected final int getGroupZ() { + return (getGroupId(2)); + } + */ + /** + * Determine the passId of an executing kernel. + * <p> + * When a <code>Kernel.execute(int globalSize, int passes)</code> is invoked for a particular kernel, the runtime will break the work into various 'groups'. + * <p> + * A kernel can use <code>getPassId()</code> to determine which pass we are in. This is ideal for 'reduce' type phases + * + * @see #getLocalId() + * @see #getGlobalId() + * @see #getGlobalSize() + * @see #getNumGroups() + * @see #getLocalSize() + * + * @return The groupId for this Kernel being executed + */ + @OpenCLDelegate + protected final int getPassId() { + return kernelState.getPassId(); + } + + /** + * Determine the local id of an executing kernel. + * <p> + * When a <code>Kernel.execute(int globalSize)</code> is invoked for a particular kernel, the runtime will break the work into + * various 'groups'. + * <code>getLocalId()</code> can be used to determine the relative id of the current kernel within a specific group. + * <p> + * The following code would capture the groupId for each kernel and map it against globalId. + * <blockquote><pre> + * final int[] localIds = new int[1024]; + * Kernel kernel = new Kernel(){ + * public void run() { + * int gid = getGlobalId(); + * localIds[gid] = getLocalId(); + * } + * }; + * kernel.execute(localIds.length); + * for (int i=0; i< values.length; i++){ + * System.out.printf("%4d %4d\n", i, localIds[i]); + * } + * </pre></blockquote> + * + * @see #getGroupId() + * @see #getGlobalId() + * @see #getGlobalSize() + * @see #getNumGroups() + * @see #getLocalSize() + * + * @return The local id for this Kernel being executed + */ + @OpenCLDelegate + protected final int getLocalId() { + return getLocalId(0); + } + + @OpenCLDelegate + protected final int getLocalId(int _dim) { + return kernelState.getLocalIds()[_dim]; + } + + /* + @OpenCLDelegate protected final int getLocalX() { + return (getLocalId(0)); + } + + @OpenCLDelegate protected final int getLocalY() { + return (getLocalId(1)); + } + + @OpenCLDelegate protected final int getLocalZ() { + return (getLocalId(2)); + } + */ + /** + * Determine the size of the group that an executing kernel is a member of. + * <p> + * When a <code>Kernel.execute(int globalSize)</code> is invoked for a particular kernel, the runtime will break the work into + * various 'groups'. <code>getLocalSize()</code> allows a kernel to determine the size of the current group. + * <p> + * Note groups may not all be the same size. In particular, if <code>(global size)%(# of compute devices)!=0</code>, the runtime can choose to dispatch kernels to + * groups with differing sizes. + * + * @see #getGroupId() + * @see #getGlobalId() + * @see #getGlobalSize() + * @see #getNumGroups() + * @see #getLocalSize() + * + * @return The size of the currently executing group. + */ + @OpenCLDelegate + protected final int getLocalSize() { + return kernelState.getRange().getLocalSize(0); + } + + @OpenCLDelegate + protected final int getLocalSize(int _dim) { + return kernelState.getRange().getLocalSize(_dim); + } + + /* + @OpenCLDelegate protected final int getLocalWidth() { + return (range.getLocalSize(0)); + } + + @OpenCLDelegate protected final int getLocalHeight() { + return (range.getLocalSize(1)); + } + + @OpenCLDelegate protected final int getLocalDepth() { + return (range.getLocalSize(2)); + } + */ + /** + * Determine the value that was passed to <code>Kernel.execute(int globalSize)</code> method. + * + * @see #getGroupId() + * @see #getGlobalId() + * @see #getNumGroups() + * @see #getLocalSize() + * + * @return The value passed to <code>Kernel.execute(int globalSize)</code> causing the current execution. + */ + @OpenCLDelegate + protected final int getGlobalSize() { + return kernelState.getRange().getGlobalSize(0); + } + + @OpenCLDelegate + protected final int getGlobalSize(int _dim) { + return kernelState.getRange().getGlobalSize(_dim); + } + + /* + @OpenCLDelegate protected final int getGlobalWidth() { + return (range.getGlobalSize(0)); + } + + @OpenCLDelegate protected final int getGlobalHeight() { + return (range.getGlobalSize(1)); + } + + @OpenCLDelegate protected final int getGlobalDepth() { + return (range.getGlobalSize(2)); + } + */ + /** + * Determine the number of groups that will be used to execute a kernel + * <p> + * When <code>Kernel.execute(int globalSize)</code> is invoked, the runtime will split the work into + * multiple 'groups'. <code>getNumGroups()</code> returns the total number of groups that will be used. + * + * @see #getGroupId() + * @see #getGlobalId() + * @see #getGlobalSize() + * @see #getNumGroups() + * @see #getLocalSize() + * + * @return The number of groups that kernels will be dispatched into. + */ + @OpenCLDelegate + protected final int getNumGroups() { + return kernelState.getRange().getNumGroups(0); + } + + @OpenCLDelegate + protected final int getNumGroups(int _dim) { + return kernelState.getRange().getNumGroups(_dim); + } + + /* + @OpenCLDelegate protected final int getNumGroupsWidth() { + return (range.getGroups(0)); + } + + @OpenCLDelegate protected final int getNumGroupsHeight() { + return (range.getGroups(1)); + } + + @OpenCLDelegate protected final int getNumGroupsDepth() { + return (range.getGroups(2)); + } + */ + /** + * The entry point of a kernel. + * + * <p> + * Every kernel must override this method. + */ + public abstract void run(); + + /** False by default. In the event that all preferred devices fail to execute a kernel, it is possible to supply an alternate (possibly non-parallel) + * execution algorithm by overriding this method to return true, and overriding {@link #executeFallbackAlgorithm(Range, int)} with the alternate + * algorithm. + */ + public boolean hasFallbackAlgorithm() { + return false; + } + + /** If {@link #hasFallbackAlgorithm()} has been overriden to return true, this method should be overriden so as to + * apply a single pass of the kernel's logic to the entire _range. + * + * <p> + * This is not normally required, as fallback to {@link JavaDevice#THREAD_POOL} will implement the algorithm in parallel. However + * in the event that thread pool execution may be prohibitively slow, this method might implement a "quick and dirty" approximation + * to the desired result (for example, a simple box-blur as opposed to a gaussian blur in an image processing application). + */ + public void executeFallbackAlgorithm(Range _range, int _passId) { + // nothing + } + + /** + * Invoking this method flags that once the current pass is complete execution should be abandoned. Due to the complexity of intercommunication + * between java (or C) and executing OpenCL, this is the best we can do for general cancellation of execution at present. OpenCL 2.0 should introduce + * pipe mechanisms which will support mid-pass cancellation easily. + * + * <p> + * Note that in the case of thread-pool/pure java execution we could do better already, using Thread.interrupt() (and/or other means) to abandon + * execution mid-pass. However at present this is not attempted. + * + * @see #execute(int, int) + * @see #execute(Range, int) + * @see #execute(String, Range, int) + */ + public void cancelMultiPass() { + if (kernelRunner == null) { + return; + } + kernelRunner.cancelMultiPass(); + } + + public int getCancelState() { + return kernelRunner == null ? KernelRunner.CANCEL_STATUS_FALSE : kernelRunner.getCancelState(); + } + + /** + * @see KernelRunner#getCurrentPass() + */ + public int getCurrentPass() { + if (kernelRunner == null) { + return KernelRunner.PASS_ID_COMPLETED_EXECUTION; + } + return kernelRunner.getCurrentPass(); + } + + /** + * @see KernelRunner#isExecuting() + */ + public boolean isExecuting() { + if (kernelRunner == null) { + return false; + } + return kernelRunner.isExecuting(); + } + + /** + * When using a Java Thread Pool Aparapi uses clone to copy the initial instance to each thread. + * + * <p> + * If you choose to override <code>clone()</code> you are responsible for delegating to <code>super.clone();</code> + */ + @Override + public Kernel clone() { + try { + final Kernel worker = (Kernel) super.clone(); + + // We need to be careful to also clone the KernelState + worker.kernelState = worker.new KernelState(kernelState); // Qualified copy constructor + + worker.kernelState.setGroupIds(new int[] {0, 0, 0}); + + worker.kernelState.setLocalIds(new int[] {0, 0, 0}); + + worker.kernelState.setGlobalIds(new int[] {0, 0, 0}); + + return worker; + } catch (final CloneNotSupportedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return (null); + } + } + + /** + * Delegates to either {@link java.lang.Math#acos(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param a value to delegate to {@link java.lang.Math#acos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(float)</a></code> + * @return {@link java.lang.Math#acos(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(float)</a></code> + * + * @see java.lang.Math#acos(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(float)</a></code> + */ + @OpenCLMapping(mapTo = "acos") + protected float acos(float a) { + return (float) Math.acos(a); + } + + /** + * Delegates to either {@link java.lang.Math#acos(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param a value to delegate to {@link java.lang.Math#acos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(double)</a></code> + * @return {@link java.lang.Math#acos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(double)</a></code> + * + * @see java.lang.Math#acos(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/acos.html">acos(double)</a></code> + */ + @OpenCLMapping(mapTo = "acos") + protected double acos(double a) { + return Math.acos(a); + } + + /** + * Delegates to either {@link java.lang.Math#asin(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#asin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(float)</a></code> + * @return {@link java.lang.Math#asin(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(float)</a></code> + * + * @see java.lang.Math#asin(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(float)</a></code> + */ + @OpenCLMapping(mapTo = "asin") + protected float asin(float _f) { + return (float) Math.asin(_f); + } + + /** + * Delegates to either {@link java.lang.Math#asin(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#asin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(double)</a></code> + * @return {@link java.lang.Math#asin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(double)</a></code> + * + * @see java.lang.Math#asin(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/asin.html">asin(double)</a></code> + */ + @OpenCLMapping(mapTo = "asin") + protected double asin(double _d) { + return Math.asin(_d); + } + + /** + * Delegates to either {@link java.lang.Math#atan(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#atan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(float)</a></code> + * @return {@link java.lang.Math#atan(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(float)</a></code> + * + * @see java.lang.Math#atan(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(float)</a></code> + */ + @OpenCLMapping(mapTo = "atan") + protected float atan(float _f) { + return (float) Math.atan(_f); + } + + /** + * Delegates to either {@link java.lang.Math#atan(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#atan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(double)</a></code> + * @return {@link java.lang.Math#atan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(double)</a></code> + * + * @see java.lang.Math#atan(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan(double)</a></code> + */ + @OpenCLMapping(mapTo = "atan") + protected double atan(double _d) { + return Math.atan(_d); + } + + /** + * Delegates to either {@link java.lang.Math#atan2(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(float, float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f1 value to delegate to first argument of {@link java.lang.Math#atan2(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(float, float)</a></code> + * @param _f2 value to delegate to second argument of {@link java.lang.Math#atan2(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(float, float)</a></code> + * @return {@link java.lang.Math#atan2(double, double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(float, float)</a></code> + * + * @see java.lang.Math#atan2(double, double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(float, float)</a></code> + */ + @OpenCLMapping(mapTo = "atan2") + protected float atan2(float _f1, float _f2) { + return (float) Math.atan2(_f1, _f2); + } + + /** + * Delegates to either {@link java.lang.Math#atan2(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(double, double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d1 value to delegate to first argument of {@link java.lang.Math#atan2(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(double, double)</a></code> + * @param _d2 value to delegate to second argument of {@link java.lang.Math#atan2(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(double, double)</a></code> + * @return {@link java.lang.Math#atan2(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(double, double)</a></code> + * + * @see java.lang.Math#atan2(double, double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atan.html">atan2(double, double)</a></code> + */ + @OpenCLMapping(mapTo = "atan2") + protected double atan2(double _d1, double _d2) { + return Math.atan2(_d1, _d2); + } + + /** + * Delegates to either {@link java.lang.Math#ceil(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#ceil(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(float)</a></code> + * @return {@link java.lang.Math#ceil(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(float)</a></code> + * + * @see java.lang.Math#ceil(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(float)</a></code> + */ + @OpenCLMapping(mapTo = "ceil") + protected float ceil(float _f) { + return (float) Math.ceil(_f); + } + + /** + * Delegates to either {@link java.lang.Math#ceil(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#ceil(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(double)</a></code> + * @return {@link java.lang.Math#ceil(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(double)</a></code> + * + * @see java.lang.Math#ceil(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ceil.html">ceil(double)</a></code> + */ + @OpenCLMapping(mapTo = "ceil") + protected double ceil(double _d) { + return Math.ceil(_d); + } + + /** + * Delegates to either {@link java.lang.Math#cos(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#cos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(float)</a></code> + * @return {@link java.lang.Math#cos(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(float)</a></code> + * + * @see java.lang.Math#cos(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(float)</a></code> + */ + @OpenCLMapping(mapTo = "cos") + protected float cos(float _f) { + return (float) Math.cos(_f); + } + + /** + * Delegates to either {@link java.lang.Math#cos(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#cos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(double)</a></code> + * @return {@link java.lang.Math#cos(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(double)</a></code> + * + * @see java.lang.Math#cos(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/cos.html">cos(double)</a></code> + */ + @OpenCLMapping(mapTo = "cos") + protected double cos(double _d) { + return Math.cos(_d); + } + + /** + * Delegates to either {@link java.lang.Math#exp(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#exp(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(float)</a></code> + * @return {@link java.lang.Math#exp(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(float)</a></code> + * + * @see java.lang.Math#exp(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(float)</a></code> + */ + @OpenCLMapping(mapTo = "exp") + protected float exp(float _f) { + return (float) Math.exp(_f); + } + + /** + * Delegates to either {@link java.lang.Math#exp(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#exp(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(double)</a></code> + * @return {@link java.lang.Math#exp(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(double)</a></code> + * + * @see java.lang.Math#exp(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/exp.html">exp(double)</a></code> + */ + @OpenCLMapping(mapTo = "exp") + protected double exp(double _d) { + return Math.exp(_d); + } + + /** + * Delegates to either {@link java.lang.Math#abs(float)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#abs(float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(float)</a></code> + * @return {@link java.lang.Math#abs(float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(float)</a></code> + * + * @see java.lang.Math#abs(float) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(float)</a></code> + */ + @OpenCLMapping(mapTo = "fabs") + protected float abs(float _f) { + return Math.abs(_f); + } + + /** + * Delegates to either {@link java.lang.Math#abs(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#abs(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(double)</a></code> + * @return {@link java.lang.Math#abs(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(double)</a></code> + * + * @see java.lang.Math#abs(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">fabs(double)</a></code> + */ + @OpenCLMapping(mapTo = "fabs") + protected double abs(double _d) { + return Math.abs(_d); + } + + /** + * Delegates to either {@link java.lang.Math#abs(int)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(int)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param n value to delegate to {@link java.lang.Math#abs(int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(int)</a></code> + * @return {@link java.lang.Math#abs(int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(int)</a></code> + * + * @see java.lang.Math#abs(int) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(int)</a></code> + */ + @OpenCLMapping(mapTo = "abs") + protected int abs(int n) { + return Math.abs(n); + } + + /** + * Delegates to either {@link java.lang.Math#abs(long)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(long)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param n value to delegate to {@link java.lang.Math#abs(long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(long)</a></code> + * @return {@link java.lang.Math#abs(long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fabs.html">abs(long)</a></code> + * + * @see java.lang.Math#abs(long) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">abs(long)</a></code> + */ + @OpenCLMapping(mapTo = "abs") + protected long abs(long n) { + return Math.abs(n); + } + + /** + * Delegates to either {@link java.lang.Math#floor(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">floor(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#floor(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(float)</a></code> + * @return {@link java.lang.Math#floor(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(float)</a></code> + * + * @see java.lang.Math#floor(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(float)</a></code> + */ + @OpenCLMapping(mapTo = "floor") + protected float floor(float _f) { + return (float) Math.floor(_f); + } + + /** + * Delegates to either {@link java.lang.Math#floor(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/abs.html">floor(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#floor(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(double)</a></code> + * @return {@link java.lang.Math#floor(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(double)</a></code> + * + * @see java.lang.Math#floor(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/floor.html">floor(double)</a></code> + */ + @OpenCLMapping(mapTo = "floor") + protected double floor(double _d) { + return Math.floor(_d); + } + + /** + * Delegates to either {@link java.lang.Math#max(float, float)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(float, float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f1 value to delegate to first argument of {@link java.lang.Math#max(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(float, float)</a></code> + * @param _f2 value to delegate to second argument of {@link java.lang.Math#max(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(float, float)</a></code> + * @return {@link java.lang.Math#max(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(float, float)</a></code> + * + * @see java.lang.Math#max(float, float) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(float, float)</a></code> + */ + @OpenCLMapping(mapTo = "fmax") + protected float max(float _f1, float _f2) { + return Math.max(_f1, _f2); + } + + /** + * Delegates to either {@link java.lang.Math#max(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(double, double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d1 value to delegate to first argument of {@link java.lang.Math#max(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(double, double)</a></code> + * @param _d2 value to delegate to second argument of {@link java.lang.Math#max(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(double, double)</a></code> + * @return {@link java.lang.Math#max(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(double, double)</a></code> + * + * @see java.lang.Math#max(double, double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmax.html">fmax(double, double)</a></code> + */ + @OpenCLMapping(mapTo = "fmax") + protected double max(double _d1, double _d2) { + return Math.max(_d1, _d2); + } + + /** + * Delegates to either {@link java.lang.Math#max(int, int)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(int, int)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param n1 value to delegate to {@link java.lang.Math#max(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(int, int)</a></code> + * @param n2 value to delegate to {@link java.lang.Math#max(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(int, int)</a></code> + * @return {@link java.lang.Math#max(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(int, int)</a></code> + * + * @see java.lang.Math#max(int, int) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(int, int)</a></code> + */ + @OpenCLMapping(mapTo = "max") + protected int max(int n1, int n2) { + return Math.max(n1, n2); + } + + /** + * Delegates to either {@link java.lang.Math#max(long, long)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(long, long)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param n1 value to delegate to first argument of {@link java.lang.Math#max(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(long, long)</a></code> + * @param n2 value to delegate to second argument of {@link java.lang.Math#max(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(long, long)</a></code> + * @return {@link java.lang.Math#max(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(long, long)</a></code> + * + * @see java.lang.Math#max(long, long) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">max(long, long)</a></code> + */ + @OpenCLMapping(mapTo = "max") + protected long max(long n1, long n2) { + return Math.max(n1, n2); + } + + /** + * Delegates to either {@link java.lang.Math#min(float, float)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(float, float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f1 value to delegate to first argument of {@link java.lang.Math#min(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(float, float)</a></code> + * @param _f2 value to delegate to second argument of {@link java.lang.Math#min(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(float, float)</a></code> + * @return {@link java.lang.Math#min(float, float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(float, float)</a></code> + * + * @see java.lang.Math#min(float, float) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(float, float)</a></code> + */ + @OpenCLMapping(mapTo = "fmin") + protected float min(float _f1, float _f2) { + return Math.min(_f1, _f2); + } + + /** + * Delegates to either {@link java.lang.Math#min(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(double, double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d1 value to delegate to first argument of {@link java.lang.Math#min(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(double, double)</a></code> + * @param _d2 value to delegate to second argument of {@link java.lang.Math#min(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(double, double)</a></code> + * @return {@link java.lang.Math#min(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(double, double)</a></code> + * + * @see java.lang.Math#min(double, double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/fmin.html">fmin(double, double)</a></code> + */ + @OpenCLMapping(mapTo = "fmin") + protected double min(double _d1, double _d2) { + return Math.min(_d1, _d2); + } + + /** + * Delegates to either {@link java.lang.Math#min(int, int)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(int, int)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param n1 value to delegate to first argument of {@link java.lang.Math#min(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(int, int)</a></code> + * @param n2 value to delegate to second argument of {@link java.lang.Math#min(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(int, int)</a></code> + * @return {@link java.lang.Math#min(int, int)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(int, int)</a></code> + * + * @see java.lang.Math#min(int, int) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(int, int)</a></code> + */ + @OpenCLMapping(mapTo = "min") + protected int min(int n1, int n2) { + return Math.min(n1, n2); + } + + /** + * Delegates to either {@link java.lang.Math#min(long, long)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(long, long)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param n1 value to delegate to first argument of {@link java.lang.Math#min(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(long, long)</a></code> + * @param n2 value to delegate to second argument of {@link java.lang.Math#min(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(long, long)</a></code> + * @return {@link java.lang.Math#min(long, long)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(long, long)</a></code> + * + * @see java.lang.Math#min(long, long) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/integerMax.html">min(long, long)</a></code> + */ + @OpenCLMapping(mapTo = "min") + protected long min(long n1, long n2) { + return Math.min(n1, n2); + } + + /** + * Delegates to either {@link java.lang.Math#log(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#log(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(float)</a></code> + * @return {@link java.lang.Math#log(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(float)</a></code> + * + * @see java.lang.Math#log(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(float)</a></code> + */ + @OpenCLMapping(mapTo = "log") + protected float log(float _f) { + return (float) Math.log(_f); + } + + /** + * Delegates to either {@link java.lang.Math#log(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#log(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(double)</a></code> + * @return {@link java.lang.Math#log(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(double)</a></code> + * + * @see java.lang.Math#log(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/log.html">log(double)</a></code> + */ + @OpenCLMapping(mapTo = "log") + protected double log(double _d) { + return Math.log(_d); + } + + /** + * Delegates to either {@link java.lang.Math#pow(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(float, float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f1 value to delegate to first argument of {@link java.lang.Math#pow(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(float, float)</a></code> + * @param _f2 value to delegate to second argument of {@link java.lang.Math#pow(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(float, float)</a></code> + * @return {@link java.lang.Math#pow(double, double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(float, float)</a></code> + * + * @see java.lang.Math#pow(double, double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(float, float)</a></code> + */ + @OpenCLMapping(mapTo = "pow") + protected float pow(float _f1, float _f2) { + return (float) Math.pow(_f1, _f2); + } + + /** + * Delegates to either {@link java.lang.Math#pow(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(double, double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d1 value to delegate to first argument of {@link java.lang.Math#pow(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(double, double)</a></code> + * @param _d2 value to delegate to second argument of {@link java.lang.Math#pow(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(double, double)</a></code> + * @return {@link java.lang.Math#pow(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(double, double)</a></code> + * + * @see java.lang.Math#pow(double, double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/pow.html">pow(double, double)</a></code> + */ + @OpenCLMapping(mapTo = "pow") + protected double pow(double _d1, double _d2) { + return Math.pow(_d1, _d2); + } + + /** + * Delegates to either {@link java.lang.Math#IEEEremainder(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(float, float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f1 value to delegate to first argument of {@link java.lang.Math#IEEEremainder(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(float, float)</a></code> + * @param _f2 value to delegate to second argument of {@link java.lang.Math#IEEEremainder(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(float, float)</a></code> + * @return {@link java.lang.Math#IEEEremainder(double, double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(float, float)</a></code> + * + * @see java.lang.Math#IEEEremainder(double, double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(float, float)</a></code> + */ + @OpenCLMapping(mapTo = "remainder") + protected float IEEEremainder(float _f1, float _f2) { + return (float) Math.IEEEremainder(_f1, _f2); + } + + /** + * Delegates to either {@link java.lang.Math#IEEEremainder(double, double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(double, double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d1 value to delegate to first argument of {@link java.lang.Math#IEEEremainder(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(double, double)</a></code> + * @param _d2 value to delegate to second argument of {@link java.lang.Math#IEEEremainder(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(double, double)</a></code> + * @return {@link java.lang.Math#IEEEremainder(double, double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(double, double)</a></code> + * + * @see java.lang.Math#IEEEremainder(double, double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/remainder.html">remainder(double, double)</a></code> + */ + @OpenCLMapping(mapTo = "remainder") + protected double IEEEremainder(double _d1, double _d2) { + return Math.IEEEremainder(_d1, _d2); + } + + /** + * Delegates to either {@link java.lang.Math#toRadians(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#toRadians(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(float)</a></code> + * @return {@link java.lang.Math#toRadians(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(float)</a></code> + * + * @see java.lang.Math#toRadians(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(float)</a></code> + */ + @OpenCLMapping(mapTo = "radians") + protected float toRadians(float _f) { + return (float) Math.toRadians(_f); + } + + /** + * Delegates to either {@link java.lang.Math#toRadians(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#toRadians(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(double)</a></code> + * @return {@link java.lang.Math#toRadians(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(double)</a></code> + * + * @see java.lang.Math#toRadians(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/radians.html">radians(double)</a></code> + */ + @OpenCLMapping(mapTo = "radians") + protected double toRadians(double _d) { + return Math.toRadians(_d); + } + + /** + * Delegates to either {@link java.lang.Math#toDegrees(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#toDegrees(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(float)</a></code> + * @return {@link java.lang.Math#toDegrees(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(float)</a></code> + * + * @see java.lang.Math#toDegrees(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(float)</a></code> + */ + @OpenCLMapping(mapTo = "degrees") + protected float toDegrees(float _f) { + return (float) Math.toDegrees(_f); + } + + /** + * Delegates to either {@link java.lang.Math#toDegrees(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#toDegrees(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(double)</a></code> + * @return {@link java.lang.Math#toDegrees(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(double)</a></code> + * + * @see java.lang.Math#toDegrees(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/degrees.html">degrees(double)</a></code> + */ + @OpenCLMapping(mapTo = "degrees") + protected double toDegrees(double _d) { + return Math.toDegrees(_d); + } + + /** + * Delegates to either {@link java.lang.Math#rint(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#rint(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(float)</a></code> + * @return {@link java.lang.Math#rint(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(float)</a></code> + * + * @see java.lang.Math#rint(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(float)</a></code> + */ + @OpenCLMapping(mapTo = "rint") + protected float rint(float _f) { + return (float) Math.rint(_f); + } + + /** + * Delegates to either {@link java.lang.Math#rint(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#rint(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(double)</a></code> + * @return {@link java.lang.Math#rint(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(double)</a></code> + * + * @see java.lang.Math#rint(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/rint.html">rint(double)</a></code> + */ + @OpenCLMapping(mapTo = "rint") + protected double rint(double _d) { + return Math.rint(_d); + } + + /** + * Delegates to either {@link java.lang.Math#round(float)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#round(float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(float)</a></code> + * @return {@link java.lang.Math#round(float)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(float)</a></code> + * + * @see java.lang.Math#round(float) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(float)</a></code> + */ + @OpenCLMapping(mapTo = "round") + protected int round(float _f) { + return Math.round(_f); + } + + /** + * Delegates to either {@link java.lang.Math#round(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#round(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(double)</a></code> + * @return {@link java.lang.Math#round(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(double)</a></code> + * + * @see java.lang.Math#round(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/round.html">round(double)</a></code> + */ + @OpenCLMapping(mapTo = "round") + protected long round(double _d) { + return Math.round(_d); + } + + /** + * Delegates to either {@link java.lang.Math#sin(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#sin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(float)</a></code> + * @return {@link java.lang.Math#sin(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(float)</a></code> + * + * @see java.lang.Math#sin(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(float)</a></code> + */ + @OpenCLMapping(mapTo = "sin") + protected float sin(float _f) { + return (float) Math.sin(_f); + } + + /** + * Delegates to either {@link java.lang.Math#sin(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#sin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(double)</a></code> + * @return {@link java.lang.Math#sin(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(double)</a></code> + * + * @see java.lang.Math#sin(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sin.html">sin(double)</a></code> + */ + @OpenCLMapping(mapTo = "sin") + protected double sin(double _d) { + return Math.sin(_d); + } + + /** + * Delegates to either {@link java.lang.Math#sqrt(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#sqrt(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(float)</a></code> + * @return {@link java.lang.Math#sqrt(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(float)</a></code> + * + * @see java.lang.Math#sqrt(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(float)</a></code> + */ + @OpenCLMapping(mapTo = "sqrt") + protected float sqrt(float _f) { + return (float) Math.sqrt(_f); + } + + /** + * Delegates to either {@link java.lang.Math#sqrt(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#sqrt(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(double)</a></code> + * @return {@link java.lang.Math#sqrt(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(double)</a></code> + * + * @see java.lang.Math#sqrt(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">sqrt(double)</a></code> + */ + @OpenCLMapping(mapTo = "sqrt") + protected double sqrt(double _d) { + return Math.sqrt(_d); + } + + /** + * Delegates to either {@link java.lang.Math#tan(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(float)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#tan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(float)</a></code> + * @return {@link java.lang.Math#tan(double)} casted to float/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(float)</a></code> + * + * @see java.lang.Math#tan(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(float)</a></code> + */ + @OpenCLMapping(mapTo = "tan") + protected float tan(float _f) { + return (float) Math.tan(_f); + } + + /** + * Delegates to either {@link java.lang.Math#tan(double)} (Java) or <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#tan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(double)</a></code> + * @return {@link java.lang.Math#tan(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(double)</a></code> + * + * @see java.lang.Math#tan(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/tan.html">tan(double)</a></code> + */ + @OpenCLMapping(mapTo = "tan") + protected double tan(double _d) { + return Math.tan(_d); + } + + // the following rsqrt and native_sqrt and native_rsqrt don't exist in java Math + // but added them here for nbody testing, not sure if we want to expose them + /** + * Computes inverse square root using {@link java.lang.Math#sqrt(double)} (Java) or delegates to <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _f value to delegate to {@link java.lang.Math#sqrt(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> + * @return <code>( 1.0f / {@link java.lang.Math#sqrt(double)} casted to float )</code>/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> + * + * @see java.lang.Math#sqrt(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> + */ + @OpenCLMapping(mapTo = "rsqrt") + protected float rsqrt(float _f) { + return (1.0f / (float) Math.sqrt(_f)); + } + + /** + * Computes inverse square root using {@link java.lang.Math#sqrt(double)} (Java) or delegates to <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> (OpenCL). + * + * User should note the differences in precision between Java and OpenCL's implementation of arithmetic functions to determine whether the difference in precision is acceptable. + * + * @param _d value to delegate to {@link java.lang.Math#sqrt(double)}/<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> + * @return <code>( 1.0f / {@link java.lang.Math#sqrt(double)} )</code> /<code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> + * + * @see java.lang.Math#sqrt(double) + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/sqrt.html">rsqrt(double)</a></code> + */ + @OpenCLMapping(mapTo = "rsqrt") + protected double rsqrt(double _d) { + return (1.0 / Math.sqrt(_d)); + } + + @OpenCLMapping(mapTo = "native_sqrt") + private float native_sqrt(float _f) { + int j = Float.floatToIntBits(_f); + j = ((1 << 29) + (j >> 1)) - (1 << 22) - 0x4c00; + return (Float.intBitsToFloat(j)); + // could add more precision using one iteration of newton's method, use the following + } + + @OpenCLMapping(mapTo = "native_rsqrt") + private float native_rsqrt(float _f) { + int j = Float.floatToIntBits(_f); + j = 0x5f3759df - (j >> 1); + final float x = (Float.intBitsToFloat(j)); + return x; + // if want more precision via one iteration of newton's method, use the following + // float fhalf = 0.5f*_f; + // return (x *(1.5f - fhalf * x * x)); + } + + // Hacked from AtomicIntegerArray.getAndAdd(i, delta) + /** + * Atomically adds <code>_delta</code> value to <code>_index</code> element of array <code>_arr</code> (Java) or delegates to <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atomic_add.html">atomic_add(volatile int*, int)</a></code> (OpenCL). + * + * + * @param _arr array for which an element value needs to be atomically incremented by <code>_delta</code> + * @param _index index of the <code>_arr</code> array that needs to be atomically incremented by <code>_delta</code> + * @param _delta value by which <code>_index</code> element of <code>_arr</code> array needs to be atomically incremented + * @return previous value of <code>_index</code> element of <code>_arr</code> array + * + * @see <code><a href="http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atomic_add.html">atomic_add(volatile int*, int)</a></code> + */ + @OpenCLMapping(atomic32 = true) + protected int atomicAdd(int[] _arr, int _index, int _delta) { + if (!Config.disableUnsafe) { + return UnsafeWrapper.atomicAdd(_arr, _index, _delta); + } else { + synchronized (_arr) { + final int previous = _arr[_index]; + _arr[_index] += _delta; + return previous; + } + } + } + + /** + * Wait for all kernels in the current group to rendezvous at this call before continuing execution. + * + * @annotion Experimental + */ + @OpenCLDelegate + @Experimental + protected final void localBarrier() { + kernelState.awaitOnLocalBarrier(); + } + + /** + * Wait for all kernels in the current group to rendezvous at this call before continuing execution. + * + * + * Java version is identical to localBarrier() + * + * @annotion Experimental + * @deprecated + */ + @OpenCLDelegate + @Experimental + @Deprecated + protected final void globalBarrier() throws DeprecatedException { + throw new DeprecatedException( + "Kernel.globalBarrier() has been deprecated. It was based an incorrect understanding of OpenCL functionality."); + } + + @OpenCLMapping(mapTo = "hypot") + protected float hypot(final float a, final float b) { + return (float) Math.hypot(a, b); + } + + @OpenCLMapping(mapTo = "hypot") + protected double hypot(final double a, final double b) { + return Math.hypot(a, b); + } + + public KernelState getKernelState() { + return kernelState; + } + + private KernelRunner prepareKernelRunner() { + if (kernelRunner == null) { + kernelRunner = new KernelRunner(this); + } + return kernelRunner; + } + + /** + * Determine the execution time of the previous Kernel.execute(range) call. + * + * Note that for the first call this will include the conversion time. + * + * @return The time spent executing the kernel (ms) + * + * @see #getConversionTime(); + * @see #getAccumulatedExecutionTime(); + * + */ + public double getExecutionTime() { + KernelProfile profile = KernelManager.instance().getProfile(getClass()); + synchronized (profile) { + return profile.getLastExecutionTime(); + } + } + + /** + * Determine the total execution time of all previous Kernel.execute(range) calls. + * + * Note that this will include the initial conversion time. + * + * @return The total time spent executing the kernel (ms) + * + * @see #getExecutionTime(); + * @see #getConversionTime(); + * + */ + public double getAccumulatedExecutionTime() { + KernelProfile profile = KernelManager.instance().getProfile(getClass()); + synchronized (profile) { + return profile.getAccumulatedTotalTime(); + } + } + + /** + * Determine the time taken to convert bytecode to OpenCL for first Kernel.execute(range) call. + * @return The time spent preparing the kernel for execution using GPU + * + * @see #getExecutionTime(); + * @see #getAccumulatedExecutionTime(); + */ + public double getConversionTime() { + KernelProfile profile = KernelManager.instance().getProfile(getClass()); + synchronized (profile) { + return profile.getLastConversionTime(); + } + } + + /** + * Start execution of <code>_range</code> kernels. + * <p> + * When <code>kernel.execute(globalSize)</code> is invoked, Aparapi will schedule the execution of <code>globalSize</code> kernels. If the execution mode is GPU then + * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. + * <p> + * @param _range The number of Kernels that we would like to initiate. + * @returnThe Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) + * + */ + public synchronized Kernel execute(Range _range) { + return (execute(_range, 1)); + } + + @Override + @SuppressWarnings("deprecation") + public String toString() { + if (executionMode == EXECUTION_MODE.AUTO) { + List<Device> preferredDevices = KernelManager.instance().getPreferences(this).getPreferredDevices(this); + StringBuilder preferredDevicesSummary = new StringBuilder("{"); + for (int i = 0; i < preferredDevices.size(); ++i) { + Device device = preferredDevices.get(i); + preferredDevicesSummary.append(device.getShortDescription()); + if (i < preferredDevices.size() - 1) { + preferredDevicesSummary.append("|"); + } + } + preferredDevicesSummary.append("}"); + return Reflection.getSimpleName(getClass()) + ", devices=" + preferredDevicesSummary.toString(); + } else { + return Reflection.getSimpleName(getClass()) + ", modes=" + executionModes + ", current = " + executionMode; + } + } + + /** + * Start execution of <code>_range</code> kernels. + * <p> + * When <code>kernel.execute(_range)</code> is 1invoked, Aparapi will schedule the execution of <code>_range</code> kernels. If the execution mode is GPU then + * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. + * <p> + * Since adding the new <code>Range class</code> this method offers backward compatibility and merely defers to <code> return (execute(Range.create(_range), 1));</code>. + * @param _range The number of Kernels that we would like to initiate. + * @returnThe Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) + * + */ + public synchronized Kernel execute(int _range) { + return (execute(createRange(_range), 1)); + } + + @SuppressWarnings("deprecation") + protected Range createRange(int _range) { + if (executionMode.equals(EXECUTION_MODE.AUTO)) { + Device device = getTargetDevice(); + Range range = Range.create(device, _range); + return range; + } else { + return Range.create(null, _range); + } + } + + /** + * Start execution of <code>_passes</code> iterations of <code>_range</code> kernels. + * <p> + * When <code>kernel.execute(_range, _passes)</code> is invoked, Aparapi will schedule the execution of <code>_reange</code> kernels. If the execution mode is GPU then + * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. + * <p> + * @param _passes The number of passes to make + * @return The Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) + * + */ + public synchronized Kernel execute(Range _range, int _passes) { + return (execute("run", _range, _passes)); + } + + /** + * Start execution of <code>_passes</code> iterations over the <code>_range</code> of kernels. + * <p> + * When <code>kernel.execute(_range)</code> is invoked, Aparapi will schedule the execution of <code>_range</code> kernels. If the execution mode is GPU then + * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. + * <p> + * Since adding the new <code>Range class</code> this method offers backward compatibility and merely defers to <code> return (execute(Range.create(_range), 1));</code>. + * @param _range The number of Kernels that we would like to initiate. + * @returnThe Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) + * + */ + public synchronized Kernel execute(int _range, int _passes) { + return (execute(createRange(_range), _passes)); + } + + /** + * Start execution of <code>globalSize</code> kernels for the given entrypoint. + * <p> + * When <code>kernel.execute("entrypoint", globalSize)</code> is invoked, Aparapi will schedule the execution of <code>globalSize</code> kernels. If the execution mode is GPU then + * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. + * <p> + * @param _entrypoint is the name of the method we wish to use as the entrypoint to the kernel + * @return The Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) + * + */ + public synchronized Kernel execute(String _entrypoint, Range _range) { + return (execute(_entrypoint, _range, 1)); + } + + /** + * Start execution of <code>globalSize</code> kernels for the given entrypoint. + * <p> + * When <code>kernel.execute("entrypoint", globalSize)</code> is invoked, Aparapi will schedule the execution of <code>globalSize</code> kernels. If the execution mode is GPU then + * the kernels will execute as OpenCL code on the GPU device. Otherwise, if the mode is JTP, the kernels will execute as a pool of Java threads on the CPU. + * <p> + * @param _entrypoint is the name of the method we wish to use as the entrypoint to the kernel + * @return The Kernel instance (this) so we can chain calls to put(arr).execute(range).get(arr) + * + */ + public synchronized Kernel execute(String _entrypoint, Range _range, int _passes) { + return prepareKernelRunner().execute(_entrypoint, _range, _passes); + } + + public boolean isAutoCleanUpArrays() { + return autoCleanUpArrays; + } + + /** + * Property which if true enables automatic calling of {@link #cleanUpArrays()} following each execution. + */ + public void setAutoCleanUpArrays(boolean autoCleanUpArrays) { + this.autoCleanUpArrays = autoCleanUpArrays; + } + + /** + * Frees the bulk of the resources used by this kernel, by setting array sizes in non-primitive {@link KernelArg}s to 1 (0 size is prohibited) and invoking kernel + * execution on a zero size range. Unlike {@link #dispose()}, this does not prohibit further invocations of this kernel, as sundry resources such as OpenCL queues are + * <b>not</b> freed by this method. + * + * <p>This allows a "dormant" Kernel to remain in existence without undue strain on GPU resources, which may be strongly preferable to disposing a Kernel and + * recreating another one later, as creation/use of a new Kernel (specifically creation of its associated OpenCL context) is expensive.</p> + * + * <p>Note that where the underlying array field is declared final, for obvious reasons it is not resized to zero.</p> + */ + public synchronized void cleanUpArrays() { + if (kernelRunner != null) { + kernelRunner.cleanUpArrays(); + } + } + + /** + * Release any resources associated with this Kernel. + * <p> + * When the execution mode is <code>CPU</code> or <code>GPU</code>, Aparapi stores some OpenCL resources in a data structure associated with the kernel instance. The + * <code>dispose()</code> method must be called to release these resources. + * <p> + * If <code>execute(int _globalSize)</code> is called after <code>dispose()</code> is called the results are undefined. + */ + public synchronized void dispose() { + if (kernelRunner != null) { + kernelRunner.dispose(); + kernelRunner = null; + } + } + + public boolean isRunningCL() { + return getTargetDevice() instanceof OpenCLDevice; + } + + public final Device getTargetDevice() { + return KernelManager.instance().getPreferences(this).getPreferredDevice(this); + } + + /** @return true by default, may be overriden to allow vetoing of a device or devices by a given Kernel instance. */ + public boolean isAllowDevice(Device _device) { + return true; + } + + /** + * @deprecated See {@link EXECUTION_MODE} + * <p> + * Return the current execution mode. + * + * Before a Kernel executes, this return value will be the execution mode as determined by the setting of + * the EXECUTION_MODE enumeration. By default, this setting is either <b>GPU</b> + * if OpenCL is available on the target system, or <b>JTP</b> otherwise. This default setting can be + * changed by calling setExecutionMode(). + * + * <p> + * After a Kernel executes, the return value will be the mode in which the Kernel actually executed. + * + * @return The current execution mode. + * + * @see #setExecutionMode(EXECUTION_MODE) + */ + @Deprecated + public EXECUTION_MODE getExecutionMode() { + return (executionMode); + } + + /** + * @deprecated See {@link EXECUTION_MODE} + * <p> + * Set the execution mode. + * <p> + * This should be regarded as a request. The real mode will be determined at runtime based on the availability of OpenCL and the characteristics of the workload. + * + * @param _executionMode the requested execution mode. + * + * @see #getExecutionMode() + */ + @Deprecated + public void setExecutionMode(EXECUTION_MODE _executionMode) { + executionMode = _executionMode; + } + + public void setExecutionModeWithoutFallback(EXECUTION_MODE _executionMode) { + executionModes.clear(); + executionModes.add(_executionMode); + currentMode = executionModes.iterator(); + executionMode = currentMode.next(); } + + /** + * @deprecated See {@link EXECUTION_MODE} + */ + @Deprecated + public void setFallbackExecutionMode() { + executionMode = EXECUTION_MODE.getFallbackExecutionMode(); + } + + final static Map<String, String> typeToLetterMap = new HashMap<String, String>(); + + static { + // only primitive types for now + typeToLetterMap.put("double", "D"); + typeToLetterMap.put("float", "F"); + typeToLetterMap.put("int", "I"); + typeToLetterMap.put("long", "J"); + typeToLetterMap.put("boolean", "Z"); + typeToLetterMap.put("byte", "B"); + typeToLetterMap.put("char", "C"); + typeToLetterMap.put("short", "S"); + typeToLetterMap.put("void", "V"); + } + + private static String descriptorToReturnTypeLetter(String desc) { + // find the letter after the closed parenthesis + return desc.substring(desc.lastIndexOf(')') + 1); + } + + private static String getReturnTypeLetter(Method meth) { + return toClassShortNameIfAny(meth.getReturnType()); + } + + private static String toClassShortNameIfAny(final Class<?> retClass) { + if (retClass.isArray()) { + return "[" + toClassShortNameIfAny(retClass.getComponentType()); + } + final String strRetClass = retClass.toString(); + final String mapping = typeToLetterMap.get(strRetClass); + // System.out.println("strRetClass = <" + strRetClass + ">, mapping = " + mapping); + if (mapping == null) + return "[" + retClass.getName() + ";"; + return mapping; + } + + public static String getMappedMethodName(MethodReferenceEntry _methodReferenceEntry) { + if (CacheEnabler.areCachesEnabled()) + return getProperty(mappedMethodNamesCache, _methodReferenceEntry, null); + String mappedName = null; + final String name = _methodReferenceEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + Class<?> currentClass = _methodReferenceEntry.getOwnerClassModel().getClassWeAreModelling(); + while (currentClass != Object.class) { + for (final Method kernelMethod : currentClass.getDeclaredMethods()) { + if (kernelMethod.isAnnotationPresent(OpenCLMapping.class)) { + // ultimately, need a way to constrain this based upon signature (to disambiguate abs(float) from abs(int); + // for Alpha, we will just disambiguate based on the return type + if (false) { + System.out.println("kernelMethod is ... " + kernelMethod.toGenericString()); + System.out.println("returnType = " + kernelMethod.getReturnType()); + System.out.println("returnTypeLetter = " + getReturnTypeLetter(kernelMethod)); + System.out.println("kernelMethod getName = " + kernelMethod.getName()); + System.out.println("methRefName = " + name + " descriptor = " + + _methodReferenceEntry.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8()); + System.out.println("descToReturnTypeLetter = " + + descriptorToReturnTypeLetter(_methodReferenceEntry.getNameAndTypeEntry().getDescriptorUTF8Entry() + .getUTF8())); + } + if (toSignature(_methodReferenceEntry).equals(toSignature(kernelMethod))) { + final OpenCLMapping annotation = kernelMethod.getAnnotation(OpenCLMapping.class); + final String mapTo = annotation.mapTo(); + if (!mapTo.equals("")) { + mappedName = mapTo; + // System.out.println("mapTo = " + mapTo); + } + } + } + } + if (mappedName != null) + break; + currentClass = currentClass.getSuperclass(); + } + // System.out.println("... in getMappedMethodName, returning = " + mappedName); + return (mappedName); + } + + public static boolean isMappedMethod(MethodReferenceEntry methodReferenceEntry) { + if (CacheEnabler.areCachesEnabled()) + return getBoolean(mappedMethodFlags, methodReferenceEntry); + boolean isMapped = false; + for (final Method kernelMethod : Kernel.class.getDeclaredMethods()) { + if (kernelMethod.isAnnotationPresent(OpenCLMapping.class)) { + if (methodReferenceEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(kernelMethod.getName())) { + + // well they have the same name ;) + isMapped = true; + } + } + } + return (isMapped); + } + + public static boolean isOpenCLDelegateMethod(MethodReferenceEntry methodReferenceEntry) { + if (CacheEnabler.areCachesEnabled()) + return getBoolean(openCLDelegateMethodFlags, methodReferenceEntry); + boolean isMapped = false; + for (final Method kernelMethod : Kernel.class.getDeclaredMethods()) { + if (kernelMethod.isAnnotationPresent(OpenCLDelegate.class)) { + if (methodReferenceEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(kernelMethod.getName())) { + + // well they have the same name ;) + isMapped = true; + } + } + } + return (isMapped); + } + + public static boolean usesAtomic32(MethodReferenceEntry methodReferenceEntry) { + if (CacheEnabler.areCachesEnabled()) + return getProperty(atomic32Cache, methodReferenceEntry, false); + for (final Method kernelMethod : Kernel.class.getDeclaredMethods()) { + if (kernelMethod.isAnnotationPresent(OpenCLMapping.class)) { + if (methodReferenceEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(kernelMethod.getName())) { + final OpenCLMapping annotation = kernelMethod.getAnnotation(OpenCLMapping.class); + return annotation.atomic32(); + } + } + } + return (false); + } + + // For alpha release atomic64 is not supported + public static boolean usesAtomic64(MethodReferenceEntry methodReferenceEntry) { + // if (CacheEnabler.areCachesEnabled()) + // return getProperty(atomic64Cache, methodReferenceEntry, false); + //for (java.lang.reflect.Method kernelMethod : Kernel.class.getDeclaredMethods()) { + // if (kernelMethod.isAnnotationPresent(Kernel.OpenCLMapping.class)) { + // if (methodReferenceEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(kernelMethod.getName())) { + // OpenCLMapping annotation = kernelMethod.getAnnotation(Kernel.OpenCLMapping.class); + // return annotation.atomic64(); + // } + // } + //} + return (false); + } + + // the flag useNullForLocalSize is useful for testing that what we compute for localSize is what OpenCL + // would also compute if we passed in null. In non-testing mode, we just call execute with the + // same localSize that we computed in getLocalSizeJNI. We don't want do publicize these of course. + // GRF we can't access this from test classes without exposing in in javadoc so I left the flag but made the test/set of the flag reflectively + boolean useNullForLocalSize = false; + + // Explicit memory management API's follow + + /** + * For dev purposes (we should remove this for production) allow us to define that this Kernel uses explicit memory management + * @param _explicit (true if we want explicit memory management) + */ + public void setExplicit(boolean _explicit) { + prepareKernelRunner().setExplicit(_explicit); + } + + /** + * For dev purposes (we should remove this for production) determine whether this Kernel uses explicit memory management + * @return (true if we kernel is using explicit memory management) + */ + public boolean isExplicit() { + return prepareKernelRunner().isExplicit(); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(long[] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(long[][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(long[][][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(double[] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(double[][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(double[][][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(float[] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(float[][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(float[][][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(int[] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(int[][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(int[][][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(byte[] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(byte[][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(byte[][][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(char[] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(char[][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(char[][][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(boolean[] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(boolean[][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel put(boolean[][][] array) { + prepareKernelRunner().put(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(long[] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(long[][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(long[][][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(double[] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(double[][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(double[][][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(float[] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(float[][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(float[][][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(int[] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(int[][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(int[][][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(byte[] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(byte[][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(byte[][][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(char[] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(char[][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(char[][][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(boolean[] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(boolean[][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Enqueue a request to return this buffer from the GPU. This method blocks until the array is available. + * @param array + * @return This kernel so that we can use the 'fluent' style API + */ + public Kernel get(boolean[][][] array) { + prepareKernelRunner().get(array); + return (this); + } + + /** + * Get the profiling information from the last successful call to Kernel.execute(). + * @return A list of ProfileInfo records + */ + public List<ProfileInfo> getProfileInfo() { + return prepareKernelRunner().getProfileInfo(); + } + + /** + * @deprecated See {@link EXECUTION_MODE}. + */ + @Deprecated + private final LinkedHashSet<EXECUTION_MODE> executionModes = (Config.executionMode != null) ? EXECUTION_MODE.getDefaultExecutionModes() : new LinkedHashSet<>(Collections.singleton(EXECUTION_MODE.AUTO)); + + /** + * @deprecated See {@link EXECUTION_MODE}. + */ + @Deprecated + private Iterator<EXECUTION_MODE> currentMode = executionModes.iterator(); + + /** + * @deprecated See {@link EXECUTION_MODE}. + */ + @Deprecated + private EXECUTION_MODE executionMode = currentMode.next(); + + /** + * @deprecated See {@link EXECUTION_MODE}. + * <p> + * set possible fallback path for execution modes. + * for example setExecutionFallbackPath(GPU,CPU,JTP) will try to use the GPU + * if it fails it will fall back to OpenCL CPU and finally it will try JTP. + */ + @Deprecated + public void addExecutionModes(EXECUTION_MODE... platforms) { + executionModes.addAll(Arrays.asList(platforms)); + currentMode = executionModes.iterator(); + executionMode = currentMode.next(); + } + + /** + * @deprecated See {@link EXECUTION_MODE}. + * @return is there another execution path we can try + */ + @Deprecated + public boolean hasNextExecutionMode() { + return currentMode.hasNext(); + } + + /** + * @deprecated See {@link EXECUTION_MODE}. + * try the next execution path in the list if there aren't any more than give up + */ + @Deprecated + public void tryNextExecutionMode() { + if (currentMode.hasNext()) { + executionMode = currentMode.next(); + } + } + + private static final ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> mappedMethodFlags = markedWith(OpenCLMapping.class); + + private static final ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> openCLDelegateMethodFlags = markedWith(OpenCLDelegate.class); + + private static final ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> atomic32Cache = cacheProperty(new ValueComputer<Class<?>, Map<String, Boolean>>() { + @Override + public Map<String, Boolean> compute(Class<?> key) { + Map<String, Boolean> properties = new HashMap<>(); + for (final Method method : key.getDeclaredMethods()) { + if (isRelevant(method) && method.isAnnotationPresent(OpenCLMapping.class)) { + properties.put(toSignature(method), method.getAnnotation(OpenCLMapping.class).atomic32()); + } + } + return properties; + } + }); + + private static final ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> atomic64Cache = cacheProperty(new ValueComputer<Class<?>, Map<String, Boolean>>() { + @Override + public Map<String, Boolean> compute(Class<?> key) { + Map<String, Boolean> properties = new HashMap<>(); + for (final Method method : key.getDeclaredMethods()) { + if (isRelevant(method) && method.isAnnotationPresent(OpenCLMapping.class)) { + properties.put(toSignature(method), method.getAnnotation(OpenCLMapping.class).atomic64()); + } + } + return properties; + } + }); + + private static boolean getBoolean(ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> methodNamesCache, + MethodReferenceEntry methodReferenceEntry) { + return getProperty(methodNamesCache, methodReferenceEntry, false); + } + + private static <A extends Annotation> ValueCache<Class<?>, Map<String, Boolean>, RuntimeException> markedWith( + final Class<A> annotationClass) { + return cacheProperty(new ValueComputer<Class<?>, Map<String, Boolean>>() { + @Override + public Map<String, Boolean> compute(Class<?> key) { + Map<String, Boolean> markedMethodNames = new HashMap<>(); + for (final Method method : key.getDeclaredMethods()) { + markedMethodNames.put(toSignature(method), method.isAnnotationPresent(annotationClass)); + } + return markedMethodNames; + } + }); + } + + static String toSignature(Method method) { + return method.getName() + getArgumentsLetters(method) + getReturnTypeLetter(method); + } + + private static String getArgumentsLetters(Method method) { + StringBuilder sb = new StringBuilder("("); + for (Class<?> parameterClass : method.getParameterTypes()) { + sb.append(toClassShortNameIfAny(parameterClass)); + } + sb.append(")"); + return sb.toString(); + } + + private static boolean isRelevant(Method method) { + return !method.isSynthetic() && !method.isBridge(); + } + + private static <V, T extends Throwable> V getProperty(ValueCache<Class<?>, Map<String, V>, T> cache, + MethodReferenceEntry methodReferenceEntry, V defaultValue) throws T { + Map<String, V> map = cache.computeIfAbsent(methodReferenceEntry.getOwnerClassModel().getClassWeAreModelling()); + String key = toSignature(methodReferenceEntry); + if (map.containsKey(key)) + return map.get(key); + return defaultValue; + } + + private static String toSignature(MethodReferenceEntry methodReferenceEntry) { + NameAndTypeEntry nameAndTypeEntry = methodReferenceEntry.getNameAndTypeEntry(); + return nameAndTypeEntry.getNameUTF8Entry().getUTF8() + nameAndTypeEntry.getDescriptorUTF8Entry().getUTF8(); + } + + private static final ValueCache<Class<?>, Map<String, String>, RuntimeException> mappedMethodNamesCache = cacheProperty(new ValueComputer<Class<?>, Map<String, String>>() { + @Override + public Map<String, String> compute(Class<?> key) { + Map<String, String> properties = new HashMap<>(); + for (final Method method : key.getDeclaredMethods()) { + if (isRelevant(method) && method.isAnnotationPresent(OpenCLMapping.class)) { + // ultimately, need a way to constrain this based upon signature (to disambiguate abs(float) from abs(int); + final OpenCLMapping annotation = method.getAnnotation(OpenCLMapping.class); + final String mapTo = annotation.mapTo(); + if (mapTo != null && !mapTo.equals("")) { + properties.put(toSignature(method), mapTo); + } + } + } + return properties; + } + }); + + private static <K, V, T extends Throwable> ValueCache<Class<?>, Map<K, V>, T> cacheProperty( + final ThrowingValueComputer<Class<?>, Map<K, V>, T> throwingValueComputer) { + return ValueCache.on(new ThrowingValueComputer<Class<?>, Map<K, V>, T>() { + @Override + public Map<K, V> compute(Class<?> key) throws T { + Map<K, V> properties = new HashMap<>(); + Deque<Class<?>> superclasses = new ArrayDeque<>(); + Class<?> currentSuperClass = key; + do { + superclasses.push(currentSuperClass); + currentSuperClass = currentSuperClass.getSuperclass(); + } while (currentSuperClass != Object.class); + for (Class<?> clazz : superclasses) { + // Overwrite property values for shadowed/overriden methods + properties.putAll(throwingValueComputer.compute(clazz)); + } + return properties; + } + }); + } + + public static void invalidateCaches() { + atomic32Cache.invalidate(); + atomic64Cache.invalidate(); + mappedMethodFlags.invalidate(); + mappedMethodNamesCache.invalidate(); + openCLDelegateMethodFlags.invalidate(); + } +} diff --git a/src/main/java/com/aparapi/ProfileInfo.java b/src/main/java/com/aparapi/ProfileInfo.java index 00aadbffa38a2107e0e90b69743075035bba5704..47b1e5da52dcfaf280ad112d5f2ed6e5b82143ae 100644 --- a/src/main/java/com/aparapi/ProfileInfo.java +++ b/src/main/java/com/aparapi/ProfileInfo.java @@ -1,138 +1,138 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi; - -public class ProfileInfo{ - - private enum TYPE { - R, - X, - W - }; // 0 = write, 1 = execute, 2 = read - - private final TYPE type; - - private final String label; - - private final long start; - - private final long end; - - private final long submit; - - private final long queued; - - /** - * Minimal constructor - * - * @param _label - * @param _type - * @param _start - * @param _end - * @param _submit - * @param _queued - */ - public ProfileInfo(String _label, int _type, long _start, long _end, long _submit, long _queued) { - type = TYPE.values()[_type]; - label = _label == null ? "exec()" : _label; - start = _start; - end = _end; - submit = _submit; - queued = _queued; - } - - public long getStart() { - return start; - } - - public long getEnd() { - return end; - } - - public long getSubmit() { - return submit; - } - - public long getQueued() { - return queued; - } - - public String getLabel() { - return (label); - } - - public TYPE getType() { - return (type); - } - - @Override public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("ProfileInfo["); - sb.append(type); - sb.append(" '"); - sb.append(label); - sb.append("' start="); - sb.append(start); - sb.append(", end="); - sb.append(end); - sb.append(", submit="); - sb.append(submit); - sb.append(", queued="); - sb.append(queued); - sb.append(", duration="); - sb.append((end - start)); - sb.append("]"); - - return sb.toString(); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi; + +public class ProfileInfo{ + + private enum TYPE { + R, + X, + W + }; // 0 = write, 1 = execute, 2 = read + + private final TYPE type; + + private final String label; + + private final long start; + + private final long end; + + private final long submit; + + private final long queued; + + /** + * Minimal constructor + * + * @param _label + * @param _type + * @param _start + * @param _end + * @param _submit + * @param _queued + */ + public ProfileInfo(String _label, int _type, long _start, long _end, long _submit, long _queued) { + type = TYPE.values()[_type]; + label = _label == null ? "exec()" : _label; + start = _start; + end = _end; + submit = _submit; + queued = _queued; + } + + public long getStart() { + return start; + } + + public long getEnd() { + return end; + } + + public long getSubmit() { + return submit; + } + + public long getQueued() { + return queued; + } + + public String getLabel() { + return (label); + } + + public TYPE getType() { + return (type); + } + + @Override public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("ProfileInfo["); + sb.append(type); + sb.append(" '"); + sb.append(label); + sb.append("' start="); + sb.append(start); + sb.append(", end="); + sb.append(end); + sb.append(", submit="); + sb.append(submit); + sb.append(", queued="); + sb.append(queued); + sb.append(", duration="); + sb.append((end - start)); + sb.append("]"); + + return sb.toString(); + } +} diff --git a/src/main/java/com/aparapi/Range.java b/src/main/java/com/aparapi/Range.java index 5ee2272500228a9b780252e9da08d0c05c1badb8..c289d66af40bc97504dfd05720646211881916b7 100644 --- a/src/main/java/com/aparapi/Range.java +++ b/src/main/java/com/aparapi/Range.java @@ -1,657 +1,657 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi; - -import com.aparapi.device.*; -import com.aparapi.internal.jni.*; - -import java.util.*; - -/** - * - * A representation of 1, 2 or 3 dimensional range of execution. - * - * This class uses factory methods to allow one, two or three dimensional ranges to be created. - * <br/> - * For a Kernel operating over the linear range 0..1024 without a specified groups size we would create a one dimensional <code>Range</code> using - * <blockquote><pre>Range.create(1024);</pre></blockquote> - * To request the same linear range but with a groupSize of 64 (range must be a multiple of group size!) we would use - * <blockquote><pre>Range.create(1024,64);</pre></blockquote> - * To request a two dimensional range over a grid (0..width)x(0..height) where width==512 and height=256 we would use - * <blockquote><pre> - * int width=512; - * int height=256; - * Range.create2D(width,height) - * </pre></blockquote> - * Again the above does not specify the group size. One will be chosen for you. If you want to specify the groupSize (say 16x8; 16 wide by 8 high) use - * <blockquote><pre> - * int width=512; - * int height=256; - * int groupWidth=16; - * int groupHeight=8; - * Range.create2D(width, height, groupWidth, groupHeight); - * </pre></blockquote> - * Finally we can request a three dimensional range using - * <blockquote><pre> - * int width=512; - * int height=256; - * int depth=8; - * Range.create3D(width, height, depth); - * </pre></blockquote> - * And can specify a group size using - * <blockquote><pre> - * int width=512; - * int height=256; - * int depth=8; - * int groupWidth=8; - * int groupHeight=4; - * int groupDepth=2 - * Range.create3D(width, height, depth, groupWidth, groupHeight, groupDepth); - * </pre></blockquote> - */ -public class Range extends RangeJNI{ - - public static final int THREADS_PER_CORE = 16; - - public static final int MAX_OPENCL_GROUP_SIZE = 256; - - public static final int MAX_GROUP_SIZE = Math.max(Runtime.getRuntime().availableProcessors() * THREADS_PER_CORE, - MAX_OPENCL_GROUP_SIZE); - - private OpenCLDevice device = null; - - private int maxWorkGroupSize; - - private int[] maxWorkItemSize = new int[] { - MAX_GROUP_SIZE, - MAX_GROUP_SIZE, - MAX_GROUP_SIZE - }; - - /** - * Minimal constructor - * - * @param _device - * @param _dims - */ - public Range(Device _device, int _dims) { - device = !(_device instanceof OpenCLDevice) ? null : (OpenCLDevice) _device; - dims = _dims; - - if (device != null) { - maxWorkItemSize = device.getMaxWorkItemSize(); - maxWorkGroupSize = device.getMaxWorkGroupSize(); - } else { - maxWorkGroupSize = MAX_GROUP_SIZE; - } - } - - /** - * Create a one dimensional range <code>0.._globalWidth</code> which is processed in groups of size _localWidth. - * <br/> - * Note that for this range to be valid : </br> <strong><code>_globalWidth > 0 && _localWidth > 0 && _localWidth < MAX_GROUP_SIZE && _globalWidth % _localWidth==0</code></strong> - * - * @param _globalWidth the overall range we wish to process - * @param _localWidth the size of the group we wish to process. - * @return A new Range with the requested dimensions - */ - public static Range create(Device _device, int _globalWidth, int _localWidth) { - final Range range = new Range(_device, 1); - - range.setGlobalSize_0(_globalWidth); - range.setLocalSize_0(_localWidth); - - range.setValid((range.getLocalSize_0() > 0) && (range.getLocalSize_0() <= range.getMaxWorkItemSize()[0]) - && (range.getLocalSize_0() <= range.getMaxWorkGroupSize()) && ((range.getGlobalSize_0() % range.getLocalSize_0()) == 0)); - - return (range); - } - - /** - * Determine the set of factors for a given value. - * @param _value The value we wish to factorize. - * @param _max an upper bound on the value that can be chosen - * @return and array of factors of _value - */ - - private static int[] getFactors(int _value, int _max) { - final int factors[] = new int[MAX_GROUP_SIZE]; - int factorIdx = 0; - - for (int possibleFactor = 1; possibleFactor <= _max; possibleFactor++) { - if ((_value % possibleFactor) == 0) { - factors[factorIdx++] = possibleFactor; - } - } - - return (Arrays.copyOf(factors, factorIdx)); - } - - /** - * Create a one dimensional range <code>0.._globalWidth</code> with an undefined group size. - * <br/> - * Note that for this range to be valid :- </br> <strong><code>_globalWidth > 0 </code></strong> - * <br/> - * The groupsize will be chosen such that _localWidth > 0 && _localWidth < MAX_GROUP_SIZE && _globalWidth % _localWidth==0 is true - * - * We extract the factors of _globalWidth and choose the highest value. - * - * @param _globalWidth the overall range we wish to process - * @return A new Range with the requested dimensions - */ - public static Range create(Device _device, int _globalWidth) { - final Range withoutLocal = create(_device, _globalWidth, 1); - - if (_device == JavaDevice.THREAD_POOL) { - withoutLocal.setLocalSize_0(Runtime.getRuntime().availableProcessors()); - withoutLocal.setLocalIsDerived(true); - return withoutLocal; - } else if (_device instanceof JavaDevice) { - withoutLocal.setLocalIsDerived(true); - return withoutLocal; - } - - if (_globalWidth == 0) { - withoutLocal.setLocalIsDerived(true); - return withoutLocal; - } - - if (withoutLocal.isValid()) { - withoutLocal.setLocalIsDerived(true); - final int[] factors = getFactors(withoutLocal.getGlobalSize_0(), withoutLocal.getMaxWorkItemSize()[0]); - - withoutLocal.setLocalSize_0(factors[factors.length - 1]); - - withoutLocal.setValid((withoutLocal.getLocalSize_0() > 0) - && (withoutLocal.getLocalSize_0() <= withoutLocal.getMaxWorkItemSize()[0]) - && (withoutLocal.getLocalSize_0() <= withoutLocal.getMaxWorkGroupSize()) - && ((withoutLocal.getGlobalSize_0() % withoutLocal.getLocalSize_0()) == 0)); - } - - return (withoutLocal); - } - - public static Range create(int _globalWidth, int _localWidth) { - final Range range = create(null, _globalWidth, _localWidth); - - return (range); - } - - public static Range create(int _globalWidth) { - final Range range = create(null, _globalWidth); - - return (range); - } - - /** - * Create a two dimensional range 0.._globalWidth x 0.._globalHeight using a group which is _localWidth x _localHeight in size. - * <br/> - * Note that for this range to be valid _globalWidth > 0 && _globalHeight >0 && _localWidth>0 && _localHeight>0 && _localWidth*_localHeight < MAX_GROUP_SIZE && _globalWidth%_localWidth==0 && _globalHeight%_localHeight==0. - * - * @param _globalWidth the overall range we wish to process - * @return - */ - public static Range create2D(Device _device, int _globalWidth, int _globalHeight, int _localWidth, int _localHeight) { - final Range range = new Range(_device, 2); - - range.setGlobalSize_0(_globalWidth); - range.setLocalSize_0(_localWidth); - range.setGlobalSize_1(_globalHeight); - range.setLocalSize_1(_localHeight); - - range.setValid((range.getLocalSize_0() > 0) && (range.getLocalSize_1() > 0) - && (range.getLocalSize_0() <= range.getMaxWorkItemSize()[0]) - && (range.getLocalSize_1() <= range.getMaxWorkItemSize()[1]) - && ((range.getLocalSize_0() * range.getLocalSize_1()) <= range.getMaxWorkGroupSize()) - && ((range.getGlobalSize_0() % range.getLocalSize_0()) == 0) - && ((range.getGlobalSize_1() % range.getLocalSize_1()) == 0)); - - return (range); - } - - /** - * Create a two dimensional range <code>0.._globalWidth * 0.._globalHeight</code> choosing suitable values for <code>localWidth</code> and <code>localHeight</code>. - * <p> - * Note that for this range to be valid <code>_globalWidth > 0 && _globalHeight >0 && _localWidth>0 && _localHeight>0 && _localWidth*_localHeight < MAX_GROUP_SIZE && _globalWidth%_localWidth==0 && _globalHeight%_localHeight==0</code>. - * - * <p> - * To determine suitable values for <code>_localWidth</code> and <code>_localHeight</code> we extract the factors for <code>_globalWidth</code> and <code>_globalHeight</code> and then - * find the largest product ( <code><= MAX_GROUP_SIZE</code>) with the lowest perimeter. - * - * <p> - * For example for <code>MAX_GROUP_SIZE</code> of 16 we favor 4x4 over 1x16. - * - * @param _globalWidth the overall range we wish to process - * @return - */ - public static Range create2D(Device _device, int _globalWidth, int _globalHeight) { - final Range withoutLocal = create2D(_device, _globalWidth, _globalHeight, 1, 1); - - if (withoutLocal.isValid()) { - withoutLocal.setLocalIsDerived(true); - final int[] widthFactors = getFactors(_globalWidth, withoutLocal.getMaxWorkItemSize()[0]); - final int[] heightFactors = getFactors(_globalHeight, withoutLocal.getMaxWorkItemSize()[1]); - - withoutLocal.setLocalSize_0(1); - withoutLocal.setLocalSize_1(1); - int max = 1; - int perimeter = 0; - - for (final int w : widthFactors) { - for (final int h : heightFactors) { - final int size = w * h; - if (size > withoutLocal.getMaxWorkGroupSize()) { - break; - } - - if (size > max) { - max = size; - perimeter = w + h; - withoutLocal.setLocalSize_0(w); - withoutLocal.setLocalSize_1(h); - } else if (size == max) { - final int localPerimeter = w + h; - if (localPerimeter < perimeter) {// is this the shortest perimeter so far - perimeter = localPerimeter; - withoutLocal.setLocalSize_0(w); - withoutLocal.setLocalSize_1(h); - } - } - } - } - - withoutLocal.setValid((withoutLocal.getLocalSize_0() > 0) && (withoutLocal.getLocalSize_1() > 0) - && (withoutLocal.getLocalSize_0() <= withoutLocal.getMaxWorkItemSize()[0]) - && (withoutLocal.getLocalSize_1() <= withoutLocal.getMaxWorkItemSize()[1]) - && ((withoutLocal.getLocalSize_0() * withoutLocal.getLocalSize_1()) <= withoutLocal.getMaxWorkGroupSize()) - && ((withoutLocal.getGlobalSize_0() % withoutLocal.getLocalSize_0()) == 0) - && ((withoutLocal.getGlobalSize_1() % withoutLocal.getLocalSize_1()) == 0)); - } - - return (withoutLocal); - } - - public static Range create2D(int _globalWidth, int _globalHeight, int _localWidth, int _localHeight) { - final Range range = create2D(null, _globalWidth, _globalHeight, _localWidth, _localHeight); - - return (range); - } - - public static Range create2D(int _globalWidth, int _globalHeight) { - final Range range = create2D(null, _globalWidth, _globalHeight); - - return (range); - } - - /** - * Create a two dimensional range <code>0.._globalWidth * 0.._globalHeight *0../_globalDepth</code> - * in groups defined by <code>localWidth</code> * <code>localHeight</code> * <code>localDepth</code>. - * <p> - * Note that for this range to be valid <code>_globalWidth > 0 && _globalHeight >0 _globalDepth >0 && _localWidth>0 && _localHeight>0 && _localDepth>0 && _localWidth*_localHeight*_localDepth < MAX_GROUP_SIZE && _globalWidth%_localWidth==0 && _globalHeight%_localHeight==0 && _globalDepth%_localDepth==0</code>. - * - * @param _globalWidth the width of the 3D grid we wish to process - * @param _globalHeight the height of the 3D grid we wish to process - * @param _globalDepth the depth of the 3D grid we wish to process - * @param _localWidth the width of the 3D group we wish to process - * @param _localHeight the height of the 3D group we wish to process - * @param _localDepth the depth of the 3D group we wish to process - * @return - */ - public static Range create3D(Device _device, int _globalWidth, int _globalHeight, int _globalDepth, int _localWidth, - int _localHeight, int _localDepth) { - final Range range = new Range(_device, 3); - - range.setGlobalSize_0(_globalWidth); - range.setLocalSize_0(_localWidth); - range.setGlobalSize_1(_globalHeight); - range.setLocalSize_1(_localHeight); - range.setGlobalSize_2(_globalDepth); - range.setLocalSize_2(_localDepth); - range.setValid((range.getLocalSize_0() > 0) && (range.getLocalSize_1() > 0) && (range.getLocalSize_2() > 0) - && ((range.getLocalSize_0() * range.getLocalSize_1() * range.getLocalSize_2()) <= range.getMaxWorkGroupSize()) - && (range.getLocalSize_0() <= range.getMaxWorkItemSize()[0]) - && (range.getLocalSize_1() <= range.getMaxWorkItemSize()[1]) - && (range.getLocalSize_2() <= range.getMaxWorkItemSize()[2]) - && ((range.getGlobalSize_0() % range.getLocalSize_0()) == 0) - && ((range.getGlobalSize_1() % range.getLocalSize_1()) == 0) - && ((range.getGlobalSize_2() % range.getLocalSize_2()) == 0)); - - return (range); - } - - /** - * Create a three dimensional range <code>0.._globalWidth * 0.._globalHeight *0../_globalDepth</code> - * choosing suitable values for <code>localWidth</code>, <code>localHeight</code> and <code>localDepth</code>. - * <p> - * Note that for this range to be valid <code>_globalWidth > 0 && _globalHeight >0 _globalDepth >0 && _localWidth>0 && _localHeight>0 && _localDepth>0 && _localWidth*_localHeight*_localDepth < MAX_GROUP_SIZE && _globalWidth%_localWidth==0 && _globalHeight%_localHeight==0 && _globalDepth%_localDepth==0</code>. - * - * <p> - * To determine suitable values for <code>_localWidth</code>,<code>_localHeight</code> and <code>_lodalDepth</code> we extract the factors for <code>_globalWidth</code>,<code>_globalHeight</code> and <code>_globalDepth</code> and then - * find the largest product ( <code><= MAX_GROUP_SIZE</code>) with the lowest perimeter. - * - * <p> - * For example for <code>MAX_GROUP_SIZE</code> of 64 we favor 4x4x4 over 1x16x16. - * - * @param _globalWidth the width of the 3D grid we wish to process - * @param _globalHeight the height of the 3D grid we wish to process - * @param _globalDepth the depth of the 3D grid we wish to process - * @return - */ - public static Range create3D(Device _device, int _globalWidth, int _globalHeight, int _globalDepth) { - final Range withoutLocal = create3D(_device, _globalWidth, _globalHeight, _globalDepth, 1, 1, 1); - - if (withoutLocal.isValid()) { - withoutLocal.setLocalIsDerived(true); - - final int[] widthFactors = getFactors(_globalWidth, withoutLocal.getMaxWorkItemSize()[0]); - final int[] heightFactors = getFactors(_globalHeight, withoutLocal.getMaxWorkItemSize()[1]); - final int[] depthFactors = getFactors(_globalDepth, withoutLocal.getMaxWorkItemSize()[2]); - - withoutLocal.setLocalSize_0(1); - withoutLocal.setLocalSize_1(1); - withoutLocal.setLocalSize_2(1); - - int max = 1; - int perimeter = 0; - - for (final int w : widthFactors) { - for (final int h : heightFactors) { - for (final int d : depthFactors) { - final int size = w * h * d; - if (size > withoutLocal.getMaxWorkGroupSize()) { - break; - } - - if (size > max) { - max = size; - perimeter = w + h + d; - withoutLocal.setLocalSize_0(w); - withoutLocal.setLocalSize_1(h); - withoutLocal.setLocalSize_2(d); - } else if (size == max) { - final int localPerimeter = w + h + d; - if (localPerimeter < perimeter) { // is this the shortest perimeter so far - perimeter = localPerimeter; - withoutLocal.setLocalSize_0(w); - withoutLocal.setLocalSize_1(w); - withoutLocal.setLocalSize_2(d); - } - } - } - } - } - - withoutLocal.setValid((withoutLocal.getLocalSize_0() > 0) - && (withoutLocal.getLocalSize_1() > 0) - && (withoutLocal.getLocalSize_2() > 0) - && ((withoutLocal.getLocalSize_0() * withoutLocal.getLocalSize_1() * withoutLocal.getLocalSize_2()) <= withoutLocal - .getMaxWorkGroupSize()) && (withoutLocal.getLocalSize_0() <= withoutLocal.getMaxWorkItemSize()[0]) - && (withoutLocal.getLocalSize_1() <= withoutLocal.getMaxWorkItemSize()[1]) - && (withoutLocal.getLocalSize_2() <= withoutLocal.getMaxWorkItemSize()[2]) - && ((withoutLocal.getGlobalSize_0() % withoutLocal.getLocalSize_0()) == 0) - && ((withoutLocal.getGlobalSize_1() % withoutLocal.getLocalSize_1()) == 0) - && ((withoutLocal.getGlobalSize_2() % withoutLocal.getLocalSize_2()) == 0)); - } - - return (withoutLocal); - } - - public static Range create3D(int _globalWidth, int _globalHeight, int _globalDepth) { - final Range range = create3D(null, _globalWidth, _globalHeight, _globalDepth); - - return (range); - } - - public static Range create3D(int _globalWidth, int _globalHeight, int _globalDepth, int _localWidth, int _localHeight, - int _localDepth) { - final Range range = create3D(null, _globalWidth, _globalHeight, _globalDepth, _localWidth, _localHeight, _localDepth); - return (range); - } - - /** - * Override {@link #toString()} - */ - @Override public String toString() { - final StringBuilder sb = new StringBuilder(); - - switch (dims) { - case 1: - sb.append("global:" + globalSize_0 + " local:" + (localIsDerived ? "(derived)" : "") + localSize_0); - break; - case 2: - sb.append("2D(global:" + globalSize_0 + "x" + globalSize_1 + " local:" + (localIsDerived ? "(derived)" : "") - + localSize_0 + "x" + localSize_1 + ")"); - break; - case 3: - sb.append("3D(global:" + globalSize_0 + "x" + globalSize_1 + "x" + globalSize_2 + " local:" - + (localIsDerived ? "(derived)" : "") + localSize_0 + "x" + localSize_1 + "x" + localSize_2 + ")"); - break; - } - - return (sb.toString()); - } - - /** - * Get the localSize (of the group) given the requested dimension - * - * @param _dim 0=width, 1=height, 2=depth - * @return The size of the group give the requested dimension - */ - public int getLocalSize(int _dim) { - return (_dim == 0 ? localSize_0 : (_dim == 1 ? localSize_1 : localSize_2)); - } - - /** - * Get the globalSize (of the range) given the requested dimension - * - * @param _dim 0=width, 1=height, 2=depth - * @return The size of the group give the requested dimension - */ - public int getGlobalSize(int _dim) { - return (_dim == 0 ? globalSize_0 : (_dim == 1 ? globalSize_1 : globalSize_2)); - } - - /** - * Get the number of groups for the given dimension. - * - * <p> - * This will essentially return globalXXXX/localXXXX for the given dimension (width, height, depth) - * @param _dim The dim we are interested in 0, 1 or 2 - * @return the number of groups for the given dimension. - */ - public int getNumGroups(int _dim) { - return (_dim == 0 ? (globalSize_0 / localSize_0) : (_dim == 1 ? (globalSize_1 / localSize_1) : (globalSize_2 / localSize_2))); - } - - /** - * - * @return The product of all valid localSize dimensions - */ - public int getWorkGroupSize() { - return localSize_0 * localSize_1 * localSize_2; - } - - public Device getDevice() { - return (device); - } - - /** - * @return the globalSize_0 - */ - public int getGlobalSize_0() { - return globalSize_0; - } - - /** - * @param globalSize_0 - * the globalSize_0 to set - */ - public void setGlobalSize_0(int globalSize_0) { - this.globalSize_0 = globalSize_0; - } - - /** - * @return the localSize_0 - */ - public int getLocalSize_0() { - return localSize_0; - } - - /** - * @param localSize_0 - * the localSize_0 to set - */ - public void setLocalSize_0(int localSize_0) { - this.localSize_0 = localSize_0; - } - - /** - * @return the globalSize_1 - */ - public int getGlobalSize_1() { - return globalSize_1; - } - - /** - * @param globalSize_1 - * the globalSize_1 to set - */ - public void setGlobalSize_1(int globalSize_1) { - this.globalSize_1 = globalSize_1; - } - - /** - * @return the localSize_1 - */ - public int getLocalSize_1() { - return localSize_1; - } - - /** - * @param localSize_1 - * the localSize_1 to set - */ - public void setLocalSize_1(int localSize_1) { - this.localSize_1 = localSize_1; - } - - /** - * @return the globalSize_2 - */ - public int getGlobalSize_2() { - return globalSize_2; - } - - /** - * @param globalSize_2 - * the globalSize_2 to set - */ - public void setGlobalSize_2(int globalSize_2) { - this.globalSize_2 = globalSize_2; - } - - /** - * @return the localSize_2 - */ - public int getLocalSize_2() { - return localSize_2; - } - - /** - * @param localSize_2 - * the localSize_2 to set - */ - public void setLocalSize_2(int localSize_2) { - this.localSize_2 = localSize_2; - } - - /** - * Get the number of dims for this Range. - * - * @return 0, 1 or 2 for one dimensional, two dimensional and three dimensional range respectively. - */ - public int getDims() { - return dims; - } - - /** - * @param dims - * the dims to set - */ - public void setDims(int dims) { - this.dims = dims; - } - - /** - * @return the valid - */ - public boolean isValid() { - return valid; - } - - /** - * @param valid - * the valid to set - */ - public void setValid(boolean valid) { - this.valid = valid; - } - - /** - * @return the localIsDerived - */ - public boolean isLocalIsDerived() { - return localIsDerived; - } - - /** - * @param localIsDerived - * the localIsDerived to set - */ - public void setLocalIsDerived(boolean localIsDerived) { - this.localIsDerived = localIsDerived; - } - - /** - * @return the maxWorkGroupSize - */ - public int getMaxWorkGroupSize() { - return maxWorkGroupSize; - } - - /** - * @param maxWorkGroupSize - * the maxWorkGroupSize to set - */ - public void setMaxWorkGroupSize(int maxWorkGroupSize) { - this.maxWorkGroupSize = maxWorkGroupSize; - } - - /** - * @return the maxWorkItemSize - */ - public int[] getMaxWorkItemSize() { - return maxWorkItemSize; - } - - /** - * @param maxWorkItemSize - * the maxWorkItemSize to set - */ - public void setMaxWorkItemSize(int[] maxWorkItemSize) { - this.maxWorkItemSize = maxWorkItemSize; - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi; + +import com.aparapi.device.*; +import com.aparapi.internal.jni.*; + +import java.util.*; + +/** + * + * A representation of 1, 2 or 3 dimensional range of execution. + * + * This class uses factory methods to allow one, two or three dimensional ranges to be created. + * <br/> + * For a Kernel operating over the linear range 0..1024 without a specified groups size we would create a one dimensional <code>Range</code> using + * <blockquote><pre>Range.create(1024);</pre></blockquote> + * To request the same linear range but with a groupSize of 64 (range must be a multiple of group size!) we would use + * <blockquote><pre>Range.create(1024,64);</pre></blockquote> + * To request a two dimensional range over a grid (0..width)x(0..height) where width==512 and height=256 we would use + * <blockquote><pre> + * int width=512; + * int height=256; + * Range.create2D(width,height) + * </pre></blockquote> + * Again the above does not specify the group size. One will be chosen for you. If you want to specify the groupSize (say 16x8; 16 wide by 8 high) use + * <blockquote><pre> + * int width=512; + * int height=256; + * int groupWidth=16; + * int groupHeight=8; + * Range.create2D(width, height, groupWidth, groupHeight); + * </pre></blockquote> + * Finally we can request a three dimensional range using + * <blockquote><pre> + * int width=512; + * int height=256; + * int depth=8; + * Range.create3D(width, height, depth); + * </pre></blockquote> + * And can specify a group size using + * <blockquote><pre> + * int width=512; + * int height=256; + * int depth=8; + * int groupWidth=8; + * int groupHeight=4; + * int groupDepth=2 + * Range.create3D(width, height, depth, groupWidth, groupHeight, groupDepth); + * </pre></blockquote> + */ +public class Range extends RangeJNI{ + + public static final int THREADS_PER_CORE = 16; + + public static final int MAX_OPENCL_GROUP_SIZE = 256; + + public static final int MAX_GROUP_SIZE = Math.max(Runtime.getRuntime().availableProcessors() * THREADS_PER_CORE, + MAX_OPENCL_GROUP_SIZE); + + private OpenCLDevice device = null; + + private int maxWorkGroupSize; + + private int[] maxWorkItemSize = new int[] { + MAX_GROUP_SIZE, + MAX_GROUP_SIZE, + MAX_GROUP_SIZE + }; + + /** + * Minimal constructor + * + * @param _device + * @param _dims + */ + public Range(Device _device, int _dims) { + device = !(_device instanceof OpenCLDevice) ? null : (OpenCLDevice) _device; + dims = _dims; + + if (device != null) { + maxWorkItemSize = device.getMaxWorkItemSize(); + maxWorkGroupSize = device.getMaxWorkGroupSize(); + } else { + maxWorkGroupSize = MAX_GROUP_SIZE; + } + } + + /** + * Create a one dimensional range <code>0.._globalWidth</code> which is processed in groups of size _localWidth. + * <br/> + * Note that for this range to be valid : </br> <strong><code>_globalWidth > 0 && _localWidth > 0 && _localWidth < MAX_GROUP_SIZE && _globalWidth % _localWidth==0</code></strong> + * + * @param _globalWidth the overall range we wish to process + * @param _localWidth the size of the group we wish to process. + * @return A new Range with the requested dimensions + */ + public static Range create(Device _device, int _globalWidth, int _localWidth) { + final Range range = new Range(_device, 1); + + range.setGlobalSize_0(_globalWidth); + range.setLocalSize_0(_localWidth); + + range.setValid((range.getLocalSize_0() > 0) && (range.getLocalSize_0() <= range.getMaxWorkItemSize()[0]) + && (range.getLocalSize_0() <= range.getMaxWorkGroupSize()) && ((range.getGlobalSize_0() % range.getLocalSize_0()) == 0)); + + return (range); + } + + /** + * Determine the set of factors for a given value. + * @param _value The value we wish to factorize. + * @param _max an upper bound on the value that can be chosen + * @return and array of factors of _value + */ + + private static int[] getFactors(int _value, int _max) { + final int factors[] = new int[MAX_GROUP_SIZE]; + int factorIdx = 0; + + for (int possibleFactor = 1; possibleFactor <= _max; possibleFactor++) { + if ((_value % possibleFactor) == 0) { + factors[factorIdx++] = possibleFactor; + } + } + + return (Arrays.copyOf(factors, factorIdx)); + } + + /** + * Create a one dimensional range <code>0.._globalWidth</code> with an undefined group size. + * <br/> + * Note that for this range to be valid :- </br> <strong><code>_globalWidth > 0 </code></strong> + * <br/> + * The groupsize will be chosen such that _localWidth > 0 && _localWidth < MAX_GROUP_SIZE && _globalWidth % _localWidth==0 is true + * + * We extract the factors of _globalWidth and choose the highest value. + * + * @param _globalWidth the overall range we wish to process + * @return A new Range with the requested dimensions + */ + public static Range create(Device _device, int _globalWidth) { + final Range withoutLocal = create(_device, _globalWidth, 1); + + if (_device == JavaDevice.THREAD_POOL) { + withoutLocal.setLocalSize_0(Runtime.getRuntime().availableProcessors()); + withoutLocal.setLocalIsDerived(true); + return withoutLocal; + } else if (_device instanceof JavaDevice) { + withoutLocal.setLocalIsDerived(true); + return withoutLocal; + } + + if (_globalWidth == 0) { + withoutLocal.setLocalIsDerived(true); + return withoutLocal; + } + + if (withoutLocal.isValid()) { + withoutLocal.setLocalIsDerived(true); + final int[] factors = getFactors(withoutLocal.getGlobalSize_0(), withoutLocal.getMaxWorkItemSize()[0]); + + withoutLocal.setLocalSize_0(factors[factors.length - 1]); + + withoutLocal.setValid((withoutLocal.getLocalSize_0() > 0) + && (withoutLocal.getLocalSize_0() <= withoutLocal.getMaxWorkItemSize()[0]) + && (withoutLocal.getLocalSize_0() <= withoutLocal.getMaxWorkGroupSize()) + && ((withoutLocal.getGlobalSize_0() % withoutLocal.getLocalSize_0()) == 0)); + } + + return (withoutLocal); + } + + public static Range create(int _globalWidth, int _localWidth) { + final Range range = create(null, _globalWidth, _localWidth); + + return (range); + } + + public static Range create(int _globalWidth) { + final Range range = create(null, _globalWidth); + + return (range); + } + + /** + * Create a two dimensional range 0.._globalWidth x 0.._globalHeight using a group which is _localWidth x _localHeight in size. + * <br/> + * Note that for this range to be valid _globalWidth > 0 && _globalHeight >0 && _localWidth>0 && _localHeight>0 && _localWidth*_localHeight < MAX_GROUP_SIZE && _globalWidth%_localWidth==0 && _globalHeight%_localHeight==0. + * + * @param _globalWidth the overall range we wish to process + * @return + */ + public static Range create2D(Device _device, int _globalWidth, int _globalHeight, int _localWidth, int _localHeight) { + final Range range = new Range(_device, 2); + + range.setGlobalSize_0(_globalWidth); + range.setLocalSize_0(_localWidth); + range.setGlobalSize_1(_globalHeight); + range.setLocalSize_1(_localHeight); + + range.setValid((range.getLocalSize_0() > 0) && (range.getLocalSize_1() > 0) + && (range.getLocalSize_0() <= range.getMaxWorkItemSize()[0]) + && (range.getLocalSize_1() <= range.getMaxWorkItemSize()[1]) + && ((range.getLocalSize_0() * range.getLocalSize_1()) <= range.getMaxWorkGroupSize()) + && ((range.getGlobalSize_0() % range.getLocalSize_0()) == 0) + && ((range.getGlobalSize_1() % range.getLocalSize_1()) == 0)); + + return (range); + } + + /** + * Create a two dimensional range <code>0.._globalWidth * 0.._globalHeight</code> choosing suitable values for <code>localWidth</code> and <code>localHeight</code>. + * <p> + * Note that for this range to be valid <code>_globalWidth > 0 && _globalHeight >0 && _localWidth>0 && _localHeight>0 && _localWidth*_localHeight < MAX_GROUP_SIZE && _globalWidth%_localWidth==0 && _globalHeight%_localHeight==0</code>. + * + * <p> + * To determine suitable values for <code>_localWidth</code> and <code>_localHeight</code> we extract the factors for <code>_globalWidth</code> and <code>_globalHeight</code> and then + * find the largest product ( <code><= MAX_GROUP_SIZE</code>) with the lowest perimeter. + * + * <p> + * For example for <code>MAX_GROUP_SIZE</code> of 16 we favor 4x4 over 1x16. + * + * @param _globalWidth the overall range we wish to process + * @return + */ + public static Range create2D(Device _device, int _globalWidth, int _globalHeight) { + final Range withoutLocal = create2D(_device, _globalWidth, _globalHeight, 1, 1); + + if (withoutLocal.isValid()) { + withoutLocal.setLocalIsDerived(true); + final int[] widthFactors = getFactors(_globalWidth, withoutLocal.getMaxWorkItemSize()[0]); + final int[] heightFactors = getFactors(_globalHeight, withoutLocal.getMaxWorkItemSize()[1]); + + withoutLocal.setLocalSize_0(1); + withoutLocal.setLocalSize_1(1); + int max = 1; + int perimeter = 0; + + for (final int w : widthFactors) { + for (final int h : heightFactors) { + final int size = w * h; + if (size > withoutLocal.getMaxWorkGroupSize()) { + break; + } + + if (size > max) { + max = size; + perimeter = w + h; + withoutLocal.setLocalSize_0(w); + withoutLocal.setLocalSize_1(h); + } else if (size == max) { + final int localPerimeter = w + h; + if (localPerimeter < perimeter) {// is this the shortest perimeter so far + perimeter = localPerimeter; + withoutLocal.setLocalSize_0(w); + withoutLocal.setLocalSize_1(h); + } + } + } + } + + withoutLocal.setValid((withoutLocal.getLocalSize_0() > 0) && (withoutLocal.getLocalSize_1() > 0) + && (withoutLocal.getLocalSize_0() <= withoutLocal.getMaxWorkItemSize()[0]) + && (withoutLocal.getLocalSize_1() <= withoutLocal.getMaxWorkItemSize()[1]) + && ((withoutLocal.getLocalSize_0() * withoutLocal.getLocalSize_1()) <= withoutLocal.getMaxWorkGroupSize()) + && ((withoutLocal.getGlobalSize_0() % withoutLocal.getLocalSize_0()) == 0) + && ((withoutLocal.getGlobalSize_1() % withoutLocal.getLocalSize_1()) == 0)); + } + + return (withoutLocal); + } + + public static Range create2D(int _globalWidth, int _globalHeight, int _localWidth, int _localHeight) { + final Range range = create2D(null, _globalWidth, _globalHeight, _localWidth, _localHeight); + + return (range); + } + + public static Range create2D(int _globalWidth, int _globalHeight) { + final Range range = create2D(null, _globalWidth, _globalHeight); + + return (range); + } + + /** + * Create a two dimensional range <code>0.._globalWidth * 0.._globalHeight *0../_globalDepth</code> + * in groups defined by <code>localWidth</code> * <code>localHeight</code> * <code>localDepth</code>. + * <p> + * Note that for this range to be valid <code>_globalWidth > 0 && _globalHeight >0 _globalDepth >0 && _localWidth>0 && _localHeight>0 && _localDepth>0 && _localWidth*_localHeight*_localDepth < MAX_GROUP_SIZE && _globalWidth%_localWidth==0 && _globalHeight%_localHeight==0 && _globalDepth%_localDepth==0</code>. + * + * @param _globalWidth the width of the 3D grid we wish to process + * @param _globalHeight the height of the 3D grid we wish to process + * @param _globalDepth the depth of the 3D grid we wish to process + * @param _localWidth the width of the 3D group we wish to process + * @param _localHeight the height of the 3D group we wish to process + * @param _localDepth the depth of the 3D group we wish to process + * @return + */ + public static Range create3D(Device _device, int _globalWidth, int _globalHeight, int _globalDepth, int _localWidth, + int _localHeight, int _localDepth) { + final Range range = new Range(_device, 3); + + range.setGlobalSize_0(_globalWidth); + range.setLocalSize_0(_localWidth); + range.setGlobalSize_1(_globalHeight); + range.setLocalSize_1(_localHeight); + range.setGlobalSize_2(_globalDepth); + range.setLocalSize_2(_localDepth); + range.setValid((range.getLocalSize_0() > 0) && (range.getLocalSize_1() > 0) && (range.getLocalSize_2() > 0) + && ((range.getLocalSize_0() * range.getLocalSize_1() * range.getLocalSize_2()) <= range.getMaxWorkGroupSize()) + && (range.getLocalSize_0() <= range.getMaxWorkItemSize()[0]) + && (range.getLocalSize_1() <= range.getMaxWorkItemSize()[1]) + && (range.getLocalSize_2() <= range.getMaxWorkItemSize()[2]) + && ((range.getGlobalSize_0() % range.getLocalSize_0()) == 0) + && ((range.getGlobalSize_1() % range.getLocalSize_1()) == 0) + && ((range.getGlobalSize_2() % range.getLocalSize_2()) == 0)); + + return (range); + } + + /** + * Create a three dimensional range <code>0.._globalWidth * 0.._globalHeight *0../_globalDepth</code> + * choosing suitable values for <code>localWidth</code>, <code>localHeight</code> and <code>localDepth</code>. + * <p> + * Note that for this range to be valid <code>_globalWidth > 0 && _globalHeight >0 _globalDepth >0 && _localWidth>0 && _localHeight>0 && _localDepth>0 && _localWidth*_localHeight*_localDepth < MAX_GROUP_SIZE && _globalWidth%_localWidth==0 && _globalHeight%_localHeight==0 && _globalDepth%_localDepth==0</code>. + * + * <p> + * To determine suitable values for <code>_localWidth</code>,<code>_localHeight</code> and <code>_lodalDepth</code> we extract the factors for <code>_globalWidth</code>,<code>_globalHeight</code> and <code>_globalDepth</code> and then + * find the largest product ( <code><= MAX_GROUP_SIZE</code>) with the lowest perimeter. + * + * <p> + * For example for <code>MAX_GROUP_SIZE</code> of 64 we favor 4x4x4 over 1x16x16. + * + * @param _globalWidth the width of the 3D grid we wish to process + * @param _globalHeight the height of the 3D grid we wish to process + * @param _globalDepth the depth of the 3D grid we wish to process + * @return + */ + public static Range create3D(Device _device, int _globalWidth, int _globalHeight, int _globalDepth) { + final Range withoutLocal = create3D(_device, _globalWidth, _globalHeight, _globalDepth, 1, 1, 1); + + if (withoutLocal.isValid()) { + withoutLocal.setLocalIsDerived(true); + + final int[] widthFactors = getFactors(_globalWidth, withoutLocal.getMaxWorkItemSize()[0]); + final int[] heightFactors = getFactors(_globalHeight, withoutLocal.getMaxWorkItemSize()[1]); + final int[] depthFactors = getFactors(_globalDepth, withoutLocal.getMaxWorkItemSize()[2]); + + withoutLocal.setLocalSize_0(1); + withoutLocal.setLocalSize_1(1); + withoutLocal.setLocalSize_2(1); + + int max = 1; + int perimeter = 0; + + for (final int w : widthFactors) { + for (final int h : heightFactors) { + for (final int d : depthFactors) { + final int size = w * h * d; + if (size > withoutLocal.getMaxWorkGroupSize()) { + break; + } + + if (size > max) { + max = size; + perimeter = w + h + d; + withoutLocal.setLocalSize_0(w); + withoutLocal.setLocalSize_1(h); + withoutLocal.setLocalSize_2(d); + } else if (size == max) { + final int localPerimeter = w + h + d; + if (localPerimeter < perimeter) { // is this the shortest perimeter so far + perimeter = localPerimeter; + withoutLocal.setLocalSize_0(w); + withoutLocal.setLocalSize_1(w); + withoutLocal.setLocalSize_2(d); + } + } + } + } + } + + withoutLocal.setValid((withoutLocal.getLocalSize_0() > 0) + && (withoutLocal.getLocalSize_1() > 0) + && (withoutLocal.getLocalSize_2() > 0) + && ((withoutLocal.getLocalSize_0() * withoutLocal.getLocalSize_1() * withoutLocal.getLocalSize_2()) <= withoutLocal + .getMaxWorkGroupSize()) && (withoutLocal.getLocalSize_0() <= withoutLocal.getMaxWorkItemSize()[0]) + && (withoutLocal.getLocalSize_1() <= withoutLocal.getMaxWorkItemSize()[1]) + && (withoutLocal.getLocalSize_2() <= withoutLocal.getMaxWorkItemSize()[2]) + && ((withoutLocal.getGlobalSize_0() % withoutLocal.getLocalSize_0()) == 0) + && ((withoutLocal.getGlobalSize_1() % withoutLocal.getLocalSize_1()) == 0) + && ((withoutLocal.getGlobalSize_2() % withoutLocal.getLocalSize_2()) == 0)); + } + + return (withoutLocal); + } + + public static Range create3D(int _globalWidth, int _globalHeight, int _globalDepth) { + final Range range = create3D(null, _globalWidth, _globalHeight, _globalDepth); + + return (range); + } + + public static Range create3D(int _globalWidth, int _globalHeight, int _globalDepth, int _localWidth, int _localHeight, + int _localDepth) { + final Range range = create3D(null, _globalWidth, _globalHeight, _globalDepth, _localWidth, _localHeight, _localDepth); + return (range); + } + + /** + * Override {@link #toString()} + */ + @Override public String toString() { + final StringBuilder sb = new StringBuilder(); + + switch (dims) { + case 1: + sb.append("global:" + globalSize_0 + " local:" + (localIsDerived ? "(derived)" : "") + localSize_0); + break; + case 2: + sb.append("2D(global:" + globalSize_0 + "x" + globalSize_1 + " local:" + (localIsDerived ? "(derived)" : "") + + localSize_0 + "x" + localSize_1 + ")"); + break; + case 3: + sb.append("3D(global:" + globalSize_0 + "x" + globalSize_1 + "x" + globalSize_2 + " local:" + + (localIsDerived ? "(derived)" : "") + localSize_0 + "x" + localSize_1 + "x" + localSize_2 + ")"); + break; + } + + return (sb.toString()); + } + + /** + * Get the localSize (of the group) given the requested dimension + * + * @param _dim 0=width, 1=height, 2=depth + * @return The size of the group give the requested dimension + */ + public int getLocalSize(int _dim) { + return (_dim == 0 ? localSize_0 : (_dim == 1 ? localSize_1 : localSize_2)); + } + + /** + * Get the globalSize (of the range) given the requested dimension + * + * @param _dim 0=width, 1=height, 2=depth + * @return The size of the group give the requested dimension + */ + public int getGlobalSize(int _dim) { + return (_dim == 0 ? globalSize_0 : (_dim == 1 ? globalSize_1 : globalSize_2)); + } + + /** + * Get the number of groups for the given dimension. + * + * <p> + * This will essentially return globalXXXX/localXXXX for the given dimension (width, height, depth) + * @param _dim The dim we are interested in 0, 1 or 2 + * @return the number of groups for the given dimension. + */ + public int getNumGroups(int _dim) { + return (_dim == 0 ? (globalSize_0 / localSize_0) : (_dim == 1 ? (globalSize_1 / localSize_1) : (globalSize_2 / localSize_2))); + } + + /** + * + * @return The product of all valid localSize dimensions + */ + public int getWorkGroupSize() { + return localSize_0 * localSize_1 * localSize_2; + } + + public Device getDevice() { + return (device); + } + + /** + * @return the globalSize_0 + */ + public int getGlobalSize_0() { + return globalSize_0; + } + + /** + * @param globalSize_0 + * the globalSize_0 to set + */ + public void setGlobalSize_0(int globalSize_0) { + this.globalSize_0 = globalSize_0; + } + + /** + * @return the localSize_0 + */ + public int getLocalSize_0() { + return localSize_0; + } + + /** + * @param localSize_0 + * the localSize_0 to set + */ + public void setLocalSize_0(int localSize_0) { + this.localSize_0 = localSize_0; + } + + /** + * @return the globalSize_1 + */ + public int getGlobalSize_1() { + return globalSize_1; + } + + /** + * @param globalSize_1 + * the globalSize_1 to set + */ + public void setGlobalSize_1(int globalSize_1) { + this.globalSize_1 = globalSize_1; + } + + /** + * @return the localSize_1 + */ + public int getLocalSize_1() { + return localSize_1; + } + + /** + * @param localSize_1 + * the localSize_1 to set + */ + public void setLocalSize_1(int localSize_1) { + this.localSize_1 = localSize_1; + } + + /** + * @return the globalSize_2 + */ + public int getGlobalSize_2() { + return globalSize_2; + } + + /** + * @param globalSize_2 + * the globalSize_2 to set + */ + public void setGlobalSize_2(int globalSize_2) { + this.globalSize_2 = globalSize_2; + } + + /** + * @return the localSize_2 + */ + public int getLocalSize_2() { + return localSize_2; + } + + /** + * @param localSize_2 + * the localSize_2 to set + */ + public void setLocalSize_2(int localSize_2) { + this.localSize_2 = localSize_2; + } + + /** + * Get the number of dims for this Range. + * + * @return 0, 1 or 2 for one dimensional, two dimensional and three dimensional range respectively. + */ + public int getDims() { + return dims; + } + + /** + * @param dims + * the dims to set + */ + public void setDims(int dims) { + this.dims = dims; + } + + /** + * @return the valid + */ + public boolean isValid() { + return valid; + } + + /** + * @param valid + * the valid to set + */ + public void setValid(boolean valid) { + this.valid = valid; + } + + /** + * @return the localIsDerived + */ + public boolean isLocalIsDerived() { + return localIsDerived; + } + + /** + * @param localIsDerived + * the localIsDerived to set + */ + public void setLocalIsDerived(boolean localIsDerived) { + this.localIsDerived = localIsDerived; + } + + /** + * @return the maxWorkGroupSize + */ + public int getMaxWorkGroupSize() { + return maxWorkGroupSize; + } + + /** + * @param maxWorkGroupSize + * the maxWorkGroupSize to set + */ + public void setMaxWorkGroupSize(int maxWorkGroupSize) { + this.maxWorkGroupSize = maxWorkGroupSize; + } + + /** + * @return the maxWorkItemSize + */ + public int[] getMaxWorkItemSize() { + return maxWorkItemSize; + } + + /** + * @param maxWorkItemSize + * the maxWorkItemSize to set + */ + public void setMaxWorkItemSize(int[] maxWorkItemSize) { + this.maxWorkItemSize = maxWorkItemSize; + } +} diff --git a/src/main/java/com/aparapi/annotation/Experimental.java b/src/main/java/com/aparapi/annotation/Experimental.java index 932b5d20438506dafc84a64b92c5101387e44391..9c62d022a38e689d10352dad1fc97ed5ee76d4eb 100644 --- a/src/main/java/com/aparapi/annotation/Experimental.java +++ b/src/main/java/com/aparapi/annotation/Experimental.java @@ -1,28 +1,28 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.annotation; - -/** - * Used to tag experimental features (methods/fields) - * <p> - * Do not rely on anything tagged as experimental, it will probably be retracted/refactored - * - * @author gfrost - * - */ -public @interface Experimental { - -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.annotation; + +/** + * Used to tag experimental features (methods/fields) + * <p> + * Do not rely on anything tagged as experimental, it will probably be retracted/refactored + * + * @author gfrost + * + */ +public @interface Experimental { + +} diff --git a/src/main/java/com/aparapi/annotation/package-info.java b/src/main/java/com/aparapi/annotation/package-info.java index 835f6363d740fe2907f03b2e5e3d38bc31cf58ac..f49ca3eafb4feffb2af11c54e422ea7eb5c4bba2 100644 --- a/src/main/java/com/aparapi/annotation/package-info.java +++ b/src/main/java/com/aparapi/annotation/package-info.java @@ -1,19 +1,19 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * - */ +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + */ package com.aparapi.annotation; \ No newline at end of file diff --git a/src/main/java/com/aparapi/device/Device.java b/src/main/java/com/aparapi/device/Device.java index e43e90b25d65cf1a35d896a2a7f503dbe8bf3da5..670cf6baea043d2cf31cd3b4fa3a03227da69eec 100644 --- a/src/main/java/com/aparapi/device/Device.java +++ b/src/main/java/com/aparapi/device/Device.java @@ -1,182 +1,182 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.device; - -import com.aparapi.*; -import com.aparapi.internal.kernel.*; - -public abstract class Device{ - - public static enum TYPE { - UNKNOWN(Integer.MAX_VALUE), - GPU(2), - CPU(3), - JTP(5), - SEQ(6), - ACC(1), - ALT(4); - - /** Heuristic ranking of device types, lower is better. */ - public final int rank; - - TYPE(int rank) { - this.rank = rank; - } - }; - - /** @deprecated use {@link KernelManager#bestDevice()} - * @see com.aparapi.device - */ - @Deprecated - public static Device best() { - return KernelManager.instance().bestDevice(); - } - - /** - * @see com.aparapi.device - */ - @SuppressWarnings("deprecation") - @Deprecated - public static Device bestGPU() { - return firstGPU(); - } - - /** - * @see com.aparapi.device - */ - @Deprecated - public static Device first(final Device.TYPE _type) { - return KernelManager.DeprecatedMethods.firstDevice(_type); - } - - /** - * @see com.aparapi.device - */ - @SuppressWarnings("deprecation") - @Deprecated - public static Device firstGPU() { - return KernelManager.DeprecatedMethods.firstDevice(TYPE.GPU); - } - - /** - * @see com.aparapi.device - */ - @SuppressWarnings("deprecation") - @Deprecated - public static Device firstCPU() { - return KernelManager.DeprecatedMethods.firstDevice(TYPE.CPU); - } - - /** - * @see com.aparapi.device - */ - @Deprecated - public static Device bestACC() { - throw new UnsupportedOperationException(); - } - - protected TYPE type = TYPE.UNKNOWN; - - protected int maxWorkGroupSize; - - protected int maxWorkItemDimensions; - - protected int[] maxWorkItemSize = new int[] { - 0, - 0, - 0 - }; - - public abstract String getShortDescription(); - - public TYPE getType() { - return type; - } - - public void setType(TYPE type) { - this.type = type; - } - - public int getMaxWorkItemDimensions() { - return maxWorkItemDimensions; - } - - public void setMaxWorkItemDimensions(int _maxWorkItemDimensions) { - maxWorkItemDimensions = _maxWorkItemDimensions; - } - - public int getMaxWorkGroupSize() { - return maxWorkGroupSize; - } - - public void setMaxWorkGroupSize(int _maxWorkGroupSize) { - maxWorkGroupSize = _maxWorkGroupSize; - } - - public int[] getMaxWorkItemSize() { - return maxWorkItemSize; - } - - public void setMaxWorkItemSize(int[] maxWorkItemSize) { - this.maxWorkItemSize = maxWorkItemSize; - } - - public Range createRange(int _globalWidth) { - return (Range.create(this, _globalWidth)); - } - - public Range createRange(int _globalWidth, int _localWidth) { - return (Range.create(this, _globalWidth, _localWidth)); - } - - public Range createRange2D(int _globalWidth, int _globalHeight) { - return (Range.create2D(this, _globalWidth, _globalHeight)); - } - - public Range createRange2D(int _globalWidth, int _globalHeight, int _localWidth, int _localHeight) { - return (Range.create2D(this, _globalWidth, _globalHeight, _localWidth, _localHeight)); - } - - public Range createRange3D(int _globalWidth, int _globalHeight, int _globalDepth) { - return (Range.create3D(this, _globalWidth, _globalHeight, _globalDepth)); - } - - public Range createRange3D(int _globalWidth, int _globalHeight, int _globalDepth, int _localWidth, int _localHeight, - int _localDepth) { - return (Range.create3D(this, _globalWidth, _globalHeight, _globalDepth, _localWidth, _localHeight, _localDepth)); - } - - public abstract long getDeviceId(); - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Device)) { - return false; - } - - Device device = (Device) o; - - return getDeviceId() == device.getDeviceId(); - } - - @Override - public int hashCode() { - return Long.valueOf(getDeviceId()).hashCode(); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.device; + +import com.aparapi.*; +import com.aparapi.internal.kernel.*; + +public abstract class Device{ + + public static enum TYPE { + UNKNOWN(Integer.MAX_VALUE), + GPU(2), + CPU(3), + JTP(5), + SEQ(6), + ACC(1), + ALT(4); + + /** Heuristic ranking of device types, lower is better. */ + public final int rank; + + TYPE(int rank) { + this.rank = rank; + } + }; + + /** @deprecated use {@link KernelManager#bestDevice()} + * @see com.aparapi.device + */ + @Deprecated + public static Device best() { + return KernelManager.instance().bestDevice(); + } + + /** + * @see com.aparapi.device + */ + @SuppressWarnings("deprecation") + @Deprecated + public static Device bestGPU() { + return firstGPU(); + } + + /** + * @see com.aparapi.device + */ + @Deprecated + public static Device first(final Device.TYPE _type) { + return KernelManager.DeprecatedMethods.firstDevice(_type); + } + + /** + * @see com.aparapi.device + */ + @SuppressWarnings("deprecation") + @Deprecated + public static Device firstGPU() { + return KernelManager.DeprecatedMethods.firstDevice(TYPE.GPU); + } + + /** + * @see com.aparapi.device + */ + @SuppressWarnings("deprecation") + @Deprecated + public static Device firstCPU() { + return KernelManager.DeprecatedMethods.firstDevice(TYPE.CPU); + } + + /** + * @see com.aparapi.device + */ + @Deprecated + public static Device bestACC() { + throw new UnsupportedOperationException(); + } + + protected TYPE type = TYPE.UNKNOWN; + + protected int maxWorkGroupSize; + + protected int maxWorkItemDimensions; + + protected int[] maxWorkItemSize = new int[] { + 0, + 0, + 0 + }; + + public abstract String getShortDescription(); + + public TYPE getType() { + return type; + } + + public void setType(TYPE type) { + this.type = type; + } + + public int getMaxWorkItemDimensions() { + return maxWorkItemDimensions; + } + + public void setMaxWorkItemDimensions(int _maxWorkItemDimensions) { + maxWorkItemDimensions = _maxWorkItemDimensions; + } + + public int getMaxWorkGroupSize() { + return maxWorkGroupSize; + } + + public void setMaxWorkGroupSize(int _maxWorkGroupSize) { + maxWorkGroupSize = _maxWorkGroupSize; + } + + public int[] getMaxWorkItemSize() { + return maxWorkItemSize; + } + + public void setMaxWorkItemSize(int[] maxWorkItemSize) { + this.maxWorkItemSize = maxWorkItemSize; + } + + public Range createRange(int _globalWidth) { + return (Range.create(this, _globalWidth)); + } + + public Range createRange(int _globalWidth, int _localWidth) { + return (Range.create(this, _globalWidth, _localWidth)); + } + + public Range createRange2D(int _globalWidth, int _globalHeight) { + return (Range.create2D(this, _globalWidth, _globalHeight)); + } + + public Range createRange2D(int _globalWidth, int _globalHeight, int _localWidth, int _localHeight) { + return (Range.create2D(this, _globalWidth, _globalHeight, _localWidth, _localHeight)); + } + + public Range createRange3D(int _globalWidth, int _globalHeight, int _globalDepth) { + return (Range.create3D(this, _globalWidth, _globalHeight, _globalDepth)); + } + + public Range createRange3D(int _globalWidth, int _globalHeight, int _globalDepth, int _localWidth, int _localHeight, + int _localDepth) { + return (Range.create3D(this, _globalWidth, _globalHeight, _globalDepth, _localWidth, _localHeight, _localDepth)); + } + + public abstract long getDeviceId(); + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Device)) { + return false; + } + + Device device = (Device) o; + + return getDeviceId() == device.getDeviceId(); + } + + @Override + public int hashCode() { + return Long.valueOf(getDeviceId()).hashCode(); + } +} diff --git a/src/main/java/com/aparapi/device/JavaDevice.java b/src/main/java/com/aparapi/device/JavaDevice.java index eaeb8abed896a24633f43022324bc6d35e7a62bc..b7c9ab47448d4229ea9bd2d78b8f6632e6d28424 100644 --- a/src/main/java/com/aparapi/device/JavaDevice.java +++ b/src/main/java/com/aparapi/device/JavaDevice.java @@ -1,47 +1,47 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.device; - -public class JavaDevice extends Device { - - public static final JavaDevice THREAD_POOL = new JavaDevice(TYPE.JTP, "Java Thread Pool", -3); - public static final JavaDevice ALTERNATIVE_ALGORITHM = new JavaDevice(TYPE.ALT, "Java Alternative Algorithm", -2); - public static final JavaDevice SEQUENTIAL = new JavaDevice(TYPE.SEQ, "Java Sequential", -1); - - private final String name; - private final long deviceId; - - private JavaDevice(TYPE _type, String _name, long deviceId) { - this.deviceId = deviceId; - this.type = _type; - this.name = _name; - } - - @Override - public String getShortDescription() { - return name; - } - - @Override - public long getDeviceId() { - return deviceId; - } - - @Override - public String toString() { - return getShortDescription(); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.device; + +public class JavaDevice extends Device { + + public static final JavaDevice THREAD_POOL = new JavaDevice(TYPE.JTP, "Java Thread Pool", -3); + public static final JavaDevice ALTERNATIVE_ALGORITHM = new JavaDevice(TYPE.ALT, "Java Alternative Algorithm", -2); + public static final JavaDevice SEQUENTIAL = new JavaDevice(TYPE.SEQ, "Java Sequential", -1); + + private final String name; + private final long deviceId; + + private JavaDevice(TYPE _type, String _name, long deviceId) { + this.deviceId = deviceId; + this.type = _type; + this.name = _name; + } + + @Override + public String getShortDescription() { + return name; + } + + @Override + public long getDeviceId() { + return deviceId; + } + + @Override + public String toString() { + return getShortDescription(); + } +} diff --git a/src/main/java/com/aparapi/device/OpenCLDevice.java b/src/main/java/com/aparapi/device/OpenCLDevice.java index fbd86e40db86903137b3cbf40ea30ca2c11568a5..ac27440fa75cd47bd4f0527478101d1d212d39c5 100644 --- a/src/main/java/com/aparapi/device/OpenCLDevice.java +++ b/src/main/java/com/aparapi/device/OpenCLDevice.java @@ -1,545 +1,545 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.device; - -import com.aparapi.opencl.OpenCL.Kernel; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.aparapi.Range; -import com.aparapi.internal.opencl.OpenCLArgDescriptor; -import com.aparapi.internal.opencl.OpenCLKernel; -import com.aparapi.internal.opencl.OpenCLPlatform; -import com.aparapi.internal.opencl.OpenCLProgram; -import com.aparapi.opencl.OpenCL; -import com.aparapi.opencl.OpenCL.Arg; -import com.aparapi.opencl.OpenCL.Constant; -import com.aparapi.opencl.OpenCL.GlobalReadOnly; -import com.aparapi.opencl.OpenCL.GlobalReadWrite; -import com.aparapi.opencl.OpenCL.GlobalWriteOnly; -import com.aparapi.opencl.OpenCL.Local; -import com.aparapi.opencl.OpenCL.Resource; -import com.aparapi.opencl.OpenCL.Source; - -public class OpenCLDevice extends Device{ - - private final OpenCLPlatform platform; - - private final long deviceId; - - private int maxComputeUnits; - - private long localMemSize; - - private long globalMemSize; - - private long maxMemAllocSize; - - private String shortDescription = null; - - private String name = null; - - /** - * Minimal constructor - * - * @param _platform - * @param _deviceId - * @param _type - */ - public OpenCLDevice(OpenCLPlatform _platform, long _deviceId, TYPE _type) { - platform = _platform; - deviceId = _deviceId; - type = _type; - } - - public OpenCLPlatform getOpenCLPlatform() { - return platform; - } - - public int getMaxComputeUnits() { - return maxComputeUnits; - } - - public void setMaxComputeUnits(int _maxComputeUnits) { - maxComputeUnits = _maxComputeUnits; - } - - public long getLocalMemSize() { - return localMemSize; - } - - public void setLocalMemSize(long _localMemSize) { - localMemSize = _localMemSize; - } - - public long getMaxMemAllocSize() { - return maxMemAllocSize; - } - - public void setMaxMemAllocSize(long _maxMemAllocSize) { - maxMemAllocSize = _maxMemAllocSize; - } - - public long getGlobalMemSize() { - return globalMemSize; - } - - public void setGlobalMemSize(long _globalMemSize) { - globalMemSize = _globalMemSize; - } - - void setMaxWorkItemSize(int _dim, int _value) { - maxWorkItemSize[_dim] = _value; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public long getDeviceId() { - return (deviceId); - } - - @Override - public String getShortDescription() { - if (shortDescription == null) { - String vendor = platform.getName(); - // Hopefully(!) this equates to the recognisable name of the vendor, e.g. "Intel", "NVIDIA", "AMD" - // Note, it is not necessarily the hardware vendor, e.g. if the AMD CPU driver (i.e. platform) is used for an Intel CPU, this will be "AMD" - String[] split = vendor.split("[\\s\\(\\)]"); // split on whitespace or on '(' or ')' since Intel use "Intel(R)" here - shortDescription = split[0] + "<" + getType() + ">"; - } - return shortDescription; - } - - public static class OpenCLInvocationHandler<T extends OpenCL<T>> implements InvocationHandler{ - private final Map<String, OpenCLKernel> map; - - private final OpenCLProgram program; - private boolean disposed = false; - public OpenCLInvocationHandler(OpenCLProgram _program, Map<String, OpenCLKernel> _map) { - program = _program; - map = _map; - disposed = false; - } - - @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (disposed){ - throw new IllegalStateException("bound interface already disposed"); - } - if (!isReservedInterfaceMethod(method)) { - final OpenCLKernel kernel = map.get(method.getName()); - if (kernel != null) { - kernel.invoke(args); - } - } else { - if (method.getName().equals("put")) { - System.out.println("put not implemented"); - - /* - for (Object arg : args) { - Class<?> argClass = arg.getClass(); - if (argClass.isArray()) { - if (argClass.getComponentType().isPrimitive()) { - OpenCLMem mem = program.getMem(arg, 0L); - if (mem == null) { - throw new IllegalStateException("can't put an array that has never been passed to a kernel " + argClass); - - } - mem.bits |= OpenCLMem.MEM_DIRTY_BIT; - } else { - throw new IllegalStateException("Only array args (of primitives) expected for put/get, cant deal with " - + argClass); - - } - } else { - throw new IllegalStateException("Only array args expected for put/get, cant deal with " + argClass); - } - } - */ - } else if (method.getName().equals("get")) { - System.out.println("get not implemented"); - /* - for (Object arg : args) { - Class<?> argClass = arg.getClass(); - if (argClass.isArray()) { - if (argClass.getComponentType().isPrimitive()) { - OpenCLMem mem = program.getMem(arg, 0L); - if (mem == null) { - throw new IllegalStateException("can't get an array that has never been passed to a kernel " + argClass); - - } - OpenCLJNI.getJNI().getMem(program, mem); - } else { - throw new IllegalStateException("Only array args (of primitives) expected for put/get, cant deal with " - + argClass); - - } - } else { - throw new IllegalStateException("Only array args expected for put/get, cant deal with " + argClass); - } - } - */ - } else if (method.getName().equals("begin")) { - System.out.println("begin not implemented"); - } else if (method.getName().equals("dispose")) { - // System.out.println("dispose"); - for (OpenCLKernel k:map.values()){ - k.dispose(); - } - program.dispose(); - map.clear(); - disposed=true; - } else if (method.getName().equals("end")) { - System.out.println("end not implemented"); - } else if (method.getName().equals("getProfileInfo")){ - proxy = program.getProfileInfo(); - } - } - return proxy; - } - } - - public List<OpenCLArgDescriptor> getArgs(Method m) { - final List<OpenCLArgDescriptor> args = new ArrayList<OpenCLArgDescriptor>(); - final Annotation[][] parameterAnnotations = m.getParameterAnnotations(); - final Class<?>[] parameterTypes = m.getParameterTypes(); - - for (int arg = 0; arg < parameterTypes.length; arg++) { - if (parameterTypes[arg].isAssignableFrom(Range.class)) { - - } else { - - long bits = 0L; - String name = null; - for (final Annotation pa : parameterAnnotations[arg]) { - if (pa instanceof GlobalReadOnly) { - name = ((GlobalReadOnly) pa).value(); - bits |= OpenCLArgDescriptor.ARG_GLOBAL_BIT | OpenCLArgDescriptor.ARG_READONLY_BIT; - } else if (pa instanceof GlobalWriteOnly) { - name = ((GlobalWriteOnly) pa).value(); - bits |= OpenCLArgDescriptor.ARG_GLOBAL_BIT | OpenCLArgDescriptor.ARG_WRITEONLY_BIT; - } else if (pa instanceof GlobalReadWrite) { - name = ((GlobalReadWrite) pa).value(); - bits |= OpenCLArgDescriptor.ARG_GLOBAL_BIT | OpenCLArgDescriptor.ARG_READWRITE_BIT; - } else if (pa instanceof Local) { - name = ((Local) pa).value(); - bits |= OpenCLArgDescriptor.ARG_LOCAL_BIT; - } else if (pa instanceof Constant) { - name = ((Constant) pa).value(); - bits |= OpenCLArgDescriptor.ARG_CONST_BIT | OpenCLArgDescriptor.ARG_READONLY_BIT; - } else if (pa instanceof Arg) { - name = ((Arg) pa).value(); - bits |= OpenCLArgDescriptor.ARG_ISARG_BIT; - } - - } - if (parameterTypes[arg].isArray()) { - if (parameterTypes[arg].isAssignableFrom(float[].class)) { - bits |= OpenCLArgDescriptor.ARG_FLOAT_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; - } else if (parameterTypes[arg].isAssignableFrom(int[].class)) { - bits |= OpenCLArgDescriptor.ARG_INT_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; - } else if (parameterTypes[arg].isAssignableFrom(double[].class)) { - bits |= OpenCLArgDescriptor.ARG_DOUBLE_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; - } else if (parameterTypes[arg].isAssignableFrom(byte[].class)) { - bits |= OpenCLArgDescriptor.ARG_BYTE_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; - } else if (parameterTypes[arg].isAssignableFrom(short[].class)) { - bits |= OpenCLArgDescriptor.ARG_SHORT_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; - } else if (parameterTypes[arg].isAssignableFrom(long[].class)) { - bits |= OpenCLArgDescriptor.ARG_LONG_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; - } - } else if (parameterTypes[arg].isPrimitive()) { - if (parameterTypes[arg].isAssignableFrom(float.class)) { - bits |= OpenCLArgDescriptor.ARG_FLOAT_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; - } else if (parameterTypes[arg].isAssignableFrom(int.class)) { - bits |= OpenCLArgDescriptor.ARG_INT_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; - } else if (parameterTypes[arg].isAssignableFrom(double.class)) { - bits |= OpenCLArgDescriptor.ARG_DOUBLE_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; - } else if (parameterTypes[arg].isAssignableFrom(byte.class)) { - bits |= OpenCLArgDescriptor.ARG_BYTE_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; - } else if (parameterTypes[arg].isAssignableFrom(short.class)) { - bits |= OpenCLArgDescriptor.ARG_SHORT_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; - } else if (parameterTypes[arg].isAssignableFrom(long.class)) { - bits |= OpenCLArgDescriptor.ARG_LONG_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; - } - } else { - System.out.println("OUch!"); - } - if (name == null) { - throw new IllegalStateException("no name!"); - } - final OpenCLArgDescriptor kernelArg = new OpenCLArgDescriptor(name, bits); - args.add(kernelArg); - - } - } - - return (args); - } - - private static boolean isReservedInterfaceMethod(Method _methods) { - return ( _methods.getName().equals("put") - || _methods.getName().equals("get") - || _methods.getName().equals("dispose") - || _methods.getName().equals("begin") - || _methods.getName().equals("end") - || _methods.getName().equals("getProfileInfo")); - } - - private String streamToString(InputStream _inputStream) { - final StringBuilder sourceBuilder = new StringBuilder(); - - if (_inputStream != null) { - - final BufferedReader reader = new BufferedReader(new InputStreamReader(_inputStream)); - - try { - for (String line = reader.readLine(); line != null; line = reader.readLine()) { - sourceBuilder.append(line).append("\n"); - } - } catch (final IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - try { - _inputStream.close(); - } catch (final IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - - return (sourceBuilder.toString()); - } - - public <T extends OpenCL<T>> T bind(Class<T> _interface, InputStream _inputStream) { - return (bind(_interface, streamToString(_inputStream))); - } - - public <T extends OpenCL<T>> T bind(Class<T> _interface) { - return (bind(_interface, (String) null)); - } - - public <T extends OpenCL<T>> T bind(Class<T> _interface, String _source) { - final Map<String, List<OpenCLArgDescriptor>> kernelNameToArgsMap = new HashMap<String, List<OpenCLArgDescriptor>>(); - - if (_source == null) { - final StringBuilder sourceBuilder = new StringBuilder(); - boolean interfaceIsAnnotated = false; - for (final Annotation a : _interface.getAnnotations()) { - if (a instanceof Source) { - final Source source = (Source) a; - sourceBuilder.append(source.value()).append("\n"); - interfaceIsAnnotated = true; - } else if (a instanceof Resource) { - final Resource sourceResource = (Resource) a; - final InputStream stream = _interface.getClassLoader().getResourceAsStream(sourceResource.value()); - sourceBuilder.append(streamToString(stream)); - interfaceIsAnnotated = true; - } - } - - if (interfaceIsAnnotated) { - // just crawl the methods (non put or get) and create kernels - for (final Method m : _interface.getDeclaredMethods()) { - if (!isReservedInterfaceMethod(m)) { - final List<OpenCLArgDescriptor> args = getArgs(m); - kernelNameToArgsMap.put(m.getName(), args); - } - } - } else { - - for (final Method m : _interface.getDeclaredMethods()) { - if (!isReservedInterfaceMethod(m)) { - for (final Annotation a : m.getAnnotations()) { - // System.out.println(" annotation "+a); - // System.out.println(" annotation type " + a.annotationType()); - if (a instanceof Kernel) { - sourceBuilder.append("__kernel void " + m.getName() + "("); - final List<OpenCLArgDescriptor> args = getArgs(m); - - boolean first = true; - for (final OpenCLArgDescriptor arg : args) { - if (first) { - first = false; - } else { - sourceBuilder.append(","); - } - sourceBuilder.append("\n " + arg); - } - - sourceBuilder.append(")"); - final Kernel kernel = (Kernel) a; - sourceBuilder.append(kernel.value()); - kernelNameToArgsMap.put(m.getName(), args); - - } - } - } - } - - } - _source = sourceBuilder.toString(); - } else { - for (final Method m : _interface.getDeclaredMethods()) { - if (!isReservedInterfaceMethod(m)) { - final List<OpenCLArgDescriptor> args = getArgs(m); - kernelNameToArgsMap.put(m.getName(), args); - } - } - } - - final OpenCLProgram program = new OpenCLProgram(this, _source).createProgram(this); - - final Map<String, OpenCLKernel> map = new HashMap<String, OpenCLKernel>(); - for (final String name : kernelNameToArgsMap.keySet()) { - final OpenCLKernel kernel = OpenCLKernel.createKernel(program, name, kernelNameToArgsMap.get(name)); - //final OpenCLKernel kernel = new OpenCLKernel(program, name, kernelNameToArgsMap.get(name)); - if (kernel == null) { - throw new IllegalStateException("kernel is null"); - } - - map.put(name, kernel); - } - - final OpenCLInvocationHandler<T> invocationHandler = new OpenCLInvocationHandler<T>(program, map); - final T instance = (T) Proxy.newProxyInstance(OpenCLDevice.class.getClassLoader(), new Class[] { - _interface, - OpenCL.class - }, invocationHandler); - - return instance; - } - - public interface DeviceSelector{ - OpenCLDevice select(OpenCLDevice _device); - } - - public interface DeviceComparitor{ - OpenCLDevice select(OpenCLDevice _deviceLhs, OpenCLDevice _deviceRhs); - } - - /** List OpenCLDevices of a given TYPE, or all OpenCLDevices if type == null. */ - public static List<OpenCLDevice> listDevices(TYPE type) { - final OpenCLPlatform platform = new OpenCLPlatform(0, null, null, null); - final ArrayList<OpenCLDevice> results = new ArrayList<>(); - - for (final OpenCLPlatform p : platform.getOpenCLPlatforms()) { - for (final OpenCLDevice device : p.getOpenCLDevices()) { - if (type == null || device.getType() == type) { - results.add(device); - } - } - } - - return results; - } - - public static OpenCLDevice select(DeviceSelector _deviceSelector) { - OpenCLDevice device = null; - final OpenCLPlatform platform = new OpenCLPlatform(0, null, null, null); - - for (final OpenCLPlatform p : platform.getOpenCLPlatforms()) { - for (final OpenCLDevice d : p.getOpenCLDevices()) { - device = _deviceSelector.select(d); - if (device != null) { - break; - } - } - if (device != null) { - break; - } - } - - return (device); - } - - public static OpenCLDevice select(DeviceComparitor _deviceComparitor) { - OpenCLDevice device = null; - final OpenCLPlatform platform = new OpenCLPlatform(0, null, null, null); - - List<OpenCLPlatform> openCLPlatforms = platform.getOpenCLPlatforms(); - for (final OpenCLPlatform p : openCLPlatforms) { - List<OpenCLDevice> openCLDevices = p.getOpenCLDevices(); - for (final OpenCLDevice d : openCLDevices) { - if (device == null) { - device = d; - } else { - device = _deviceComparitor.select(device, d); - } - } - } - - return (device); - } - - public static OpenCLDevice select(DeviceComparitor _deviceComparitor, Device.TYPE _type) { - OpenCLDevice device = null; - final OpenCLPlatform platform = new OpenCLPlatform(0, null, null, null); - - for (final OpenCLPlatform p : platform.getOpenCLPlatforms()) { - for (final OpenCLDevice d : p.getOpenCLDevices()) { - if (d.getType() != _type) continue; - if (device == null) { - device = d; - } else { - device = _deviceComparitor.select(device, d); - } - } - } - - return (device); - } - - @Override public String toString() { - final StringBuilder s = new StringBuilder("{"); - boolean first = true; - for (final int workItemSize : maxWorkItemSize) { - if (first) { - first = false; - } else { - s.append(", "); - } - - s.append(workItemSize); - } - - s.append("}"); - - return ("Device " + deviceId + "\n vendor = " + getOpenCLPlatform().getVendor() - + "\n type:" + type + "\n maxComputeUnits=" + maxComputeUnits + "\n maxWorkItemDimensions=" - + maxWorkItemDimensions + "\n maxWorkItemSizes=" + s + "\n maxWorkWorkGroupSize=" + maxWorkGroupSize - + "\n globalMemSize=" + globalMemSize + "\n localMemSize=" + localMemSize); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.device; + +import com.aparapi.opencl.OpenCL.Kernel; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.aparapi.Range; +import com.aparapi.internal.opencl.OpenCLArgDescriptor; +import com.aparapi.internal.opencl.OpenCLKernel; +import com.aparapi.internal.opencl.OpenCLPlatform; +import com.aparapi.internal.opencl.OpenCLProgram; +import com.aparapi.opencl.OpenCL; +import com.aparapi.opencl.OpenCL.Arg; +import com.aparapi.opencl.OpenCL.Constant; +import com.aparapi.opencl.OpenCL.GlobalReadOnly; +import com.aparapi.opencl.OpenCL.GlobalReadWrite; +import com.aparapi.opencl.OpenCL.GlobalWriteOnly; +import com.aparapi.opencl.OpenCL.Local; +import com.aparapi.opencl.OpenCL.Resource; +import com.aparapi.opencl.OpenCL.Source; + +public class OpenCLDevice extends Device{ + + private final OpenCLPlatform platform; + + private final long deviceId; + + private int maxComputeUnits; + + private long localMemSize; + + private long globalMemSize; + + private long maxMemAllocSize; + + private String shortDescription = null; + + private String name = null; + + /** + * Minimal constructor + * + * @param _platform + * @param _deviceId + * @param _type + */ + public OpenCLDevice(OpenCLPlatform _platform, long _deviceId, TYPE _type) { + platform = _platform; + deviceId = _deviceId; + type = _type; + } + + public OpenCLPlatform getOpenCLPlatform() { + return platform; + } + + public int getMaxComputeUnits() { + return maxComputeUnits; + } + + public void setMaxComputeUnits(int _maxComputeUnits) { + maxComputeUnits = _maxComputeUnits; + } + + public long getLocalMemSize() { + return localMemSize; + } + + public void setLocalMemSize(long _localMemSize) { + localMemSize = _localMemSize; + } + + public long getMaxMemAllocSize() { + return maxMemAllocSize; + } + + public void setMaxMemAllocSize(long _maxMemAllocSize) { + maxMemAllocSize = _maxMemAllocSize; + } + + public long getGlobalMemSize() { + return globalMemSize; + } + + public void setGlobalMemSize(long _globalMemSize) { + globalMemSize = _globalMemSize; + } + + void setMaxWorkItemSize(int _dim, int _value) { + maxWorkItemSize[_dim] = _value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public long getDeviceId() { + return (deviceId); + } + + @Override + public String getShortDescription() { + if (shortDescription == null) { + String vendor = platform.getName(); + // Hopefully(!) this equates to the recognisable name of the vendor, e.g. "Intel", "NVIDIA", "AMD" + // Note, it is not necessarily the hardware vendor, e.g. if the AMD CPU driver (i.e. platform) is used for an Intel CPU, this will be "AMD" + String[] split = vendor.split("[\\s\\(\\)]"); // split on whitespace or on '(' or ')' since Intel use "Intel(R)" here + shortDescription = split[0] + "<" + getType() + ">"; + } + return shortDescription; + } + + public static class OpenCLInvocationHandler<T extends OpenCL<T>> implements InvocationHandler{ + private final Map<String, OpenCLKernel> map; + + private final OpenCLProgram program; + private boolean disposed = false; + public OpenCLInvocationHandler(OpenCLProgram _program, Map<String, OpenCLKernel> _map) { + program = _program; + map = _map; + disposed = false; + } + + @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (disposed){ + throw new IllegalStateException("bound interface already disposed"); + } + if (!isReservedInterfaceMethod(method)) { + final OpenCLKernel kernel = map.get(method.getName()); + if (kernel != null) { + kernel.invoke(args); + } + } else { + if (method.getName().equals("put")) { + System.out.println("put not implemented"); + + /* + for (Object arg : args) { + Class<?> argClass = arg.getClass(); + if (argClass.isArray()) { + if (argClass.getComponentType().isPrimitive()) { + OpenCLMem mem = program.getMem(arg, 0L); + if (mem == null) { + throw new IllegalStateException("can't put an array that has never been passed to a kernel " + argClass); + + } + mem.bits |= OpenCLMem.MEM_DIRTY_BIT; + } else { + throw new IllegalStateException("Only array args (of primitives) expected for put/get, cant deal with " + + argClass); + + } + } else { + throw new IllegalStateException("Only array args expected for put/get, cant deal with " + argClass); + } + } + */ + } else if (method.getName().equals("get")) { + System.out.println("get not implemented"); + /* + for (Object arg : args) { + Class<?> argClass = arg.getClass(); + if (argClass.isArray()) { + if (argClass.getComponentType().isPrimitive()) { + OpenCLMem mem = program.getMem(arg, 0L); + if (mem == null) { + throw new IllegalStateException("can't get an array that has never been passed to a kernel " + argClass); + + } + OpenCLJNI.getJNI().getMem(program, mem); + } else { + throw new IllegalStateException("Only array args (of primitives) expected for put/get, cant deal with " + + argClass); + + } + } else { + throw new IllegalStateException("Only array args expected for put/get, cant deal with " + argClass); + } + } + */ + } else if (method.getName().equals("begin")) { + System.out.println("begin not implemented"); + } else if (method.getName().equals("dispose")) { + // System.out.println("dispose"); + for (OpenCLKernel k:map.values()){ + k.dispose(); + } + program.dispose(); + map.clear(); + disposed=true; + } else if (method.getName().equals("end")) { + System.out.println("end not implemented"); + } else if (method.getName().equals("getProfileInfo")){ + proxy = program.getProfileInfo(); + } + } + return proxy; + } + } + + public List<OpenCLArgDescriptor> getArgs(Method m) { + final List<OpenCLArgDescriptor> args = new ArrayList<OpenCLArgDescriptor>(); + final Annotation[][] parameterAnnotations = m.getParameterAnnotations(); + final Class<?>[] parameterTypes = m.getParameterTypes(); + + for (int arg = 0; arg < parameterTypes.length; arg++) { + if (parameterTypes[arg].isAssignableFrom(Range.class)) { + + } else { + + long bits = 0L; + String name = null; + for (final Annotation pa : parameterAnnotations[arg]) { + if (pa instanceof GlobalReadOnly) { + name = ((GlobalReadOnly) pa).value(); + bits |= OpenCLArgDescriptor.ARG_GLOBAL_BIT | OpenCLArgDescriptor.ARG_READONLY_BIT; + } else if (pa instanceof GlobalWriteOnly) { + name = ((GlobalWriteOnly) pa).value(); + bits |= OpenCLArgDescriptor.ARG_GLOBAL_BIT | OpenCLArgDescriptor.ARG_WRITEONLY_BIT; + } else if (pa instanceof GlobalReadWrite) { + name = ((GlobalReadWrite) pa).value(); + bits |= OpenCLArgDescriptor.ARG_GLOBAL_BIT | OpenCLArgDescriptor.ARG_READWRITE_BIT; + } else if (pa instanceof Local) { + name = ((Local) pa).value(); + bits |= OpenCLArgDescriptor.ARG_LOCAL_BIT; + } else if (pa instanceof Constant) { + name = ((Constant) pa).value(); + bits |= OpenCLArgDescriptor.ARG_CONST_BIT | OpenCLArgDescriptor.ARG_READONLY_BIT; + } else if (pa instanceof Arg) { + name = ((Arg) pa).value(); + bits |= OpenCLArgDescriptor.ARG_ISARG_BIT; + } + + } + if (parameterTypes[arg].isArray()) { + if (parameterTypes[arg].isAssignableFrom(float[].class)) { + bits |= OpenCLArgDescriptor.ARG_FLOAT_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; + } else if (parameterTypes[arg].isAssignableFrom(int[].class)) { + bits |= OpenCLArgDescriptor.ARG_INT_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; + } else if (parameterTypes[arg].isAssignableFrom(double[].class)) { + bits |= OpenCLArgDescriptor.ARG_DOUBLE_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; + } else if (parameterTypes[arg].isAssignableFrom(byte[].class)) { + bits |= OpenCLArgDescriptor.ARG_BYTE_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; + } else if (parameterTypes[arg].isAssignableFrom(short[].class)) { + bits |= OpenCLArgDescriptor.ARG_SHORT_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; + } else if (parameterTypes[arg].isAssignableFrom(long[].class)) { + bits |= OpenCLArgDescriptor.ARG_LONG_BIT | OpenCLArgDescriptor.ARG_ARRAY_BIT; + } + } else if (parameterTypes[arg].isPrimitive()) { + if (parameterTypes[arg].isAssignableFrom(float.class)) { + bits |= OpenCLArgDescriptor.ARG_FLOAT_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; + } else if (parameterTypes[arg].isAssignableFrom(int.class)) { + bits |= OpenCLArgDescriptor.ARG_INT_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; + } else if (parameterTypes[arg].isAssignableFrom(double.class)) { + bits |= OpenCLArgDescriptor.ARG_DOUBLE_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; + } else if (parameterTypes[arg].isAssignableFrom(byte.class)) { + bits |= OpenCLArgDescriptor.ARG_BYTE_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; + } else if (parameterTypes[arg].isAssignableFrom(short.class)) { + bits |= OpenCLArgDescriptor.ARG_SHORT_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; + } else if (parameterTypes[arg].isAssignableFrom(long.class)) { + bits |= OpenCLArgDescriptor.ARG_LONG_BIT | OpenCLArgDescriptor.ARG_PRIMITIVE_BIT; + } + } else { + System.out.println("OUch!"); + } + if (name == null) { + throw new IllegalStateException("no name!"); + } + final OpenCLArgDescriptor kernelArg = new OpenCLArgDescriptor(name, bits); + args.add(kernelArg); + + } + } + + return (args); + } + + private static boolean isReservedInterfaceMethod(Method _methods) { + return ( _methods.getName().equals("put") + || _methods.getName().equals("get") + || _methods.getName().equals("dispose") + || _methods.getName().equals("begin") + || _methods.getName().equals("end") + || _methods.getName().equals("getProfileInfo")); + } + + private String streamToString(InputStream _inputStream) { + final StringBuilder sourceBuilder = new StringBuilder(); + + if (_inputStream != null) { + + final BufferedReader reader = new BufferedReader(new InputStreamReader(_inputStream)); + + try { + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + sourceBuilder.append(line).append("\n"); + } + } catch (final IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + _inputStream.close(); + } catch (final IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + + return (sourceBuilder.toString()); + } + + public <T extends OpenCL<T>> T bind(Class<T> _interface, InputStream _inputStream) { + return (bind(_interface, streamToString(_inputStream))); + } + + public <T extends OpenCL<T>> T bind(Class<T> _interface) { + return (bind(_interface, (String) null)); + } + + public <T extends OpenCL<T>> T bind(Class<T> _interface, String _source) { + final Map<String, List<OpenCLArgDescriptor>> kernelNameToArgsMap = new HashMap<String, List<OpenCLArgDescriptor>>(); + + if (_source == null) { + final StringBuilder sourceBuilder = new StringBuilder(); + boolean interfaceIsAnnotated = false; + for (final Annotation a : _interface.getAnnotations()) { + if (a instanceof Source) { + final Source source = (Source) a; + sourceBuilder.append(source.value()).append("\n"); + interfaceIsAnnotated = true; + } else if (a instanceof Resource) { + final Resource sourceResource = (Resource) a; + final InputStream stream = _interface.getClassLoader().getResourceAsStream(sourceResource.value()); + sourceBuilder.append(streamToString(stream)); + interfaceIsAnnotated = true; + } + } + + if (interfaceIsAnnotated) { + // just crawl the methods (non put or get) and create kernels + for (final Method m : _interface.getDeclaredMethods()) { + if (!isReservedInterfaceMethod(m)) { + final List<OpenCLArgDescriptor> args = getArgs(m); + kernelNameToArgsMap.put(m.getName(), args); + } + } + } else { + + for (final Method m : _interface.getDeclaredMethods()) { + if (!isReservedInterfaceMethod(m)) { + for (final Annotation a : m.getAnnotations()) { + // System.out.println(" annotation "+a); + // System.out.println(" annotation type " + a.annotationType()); + if (a instanceof Kernel) { + sourceBuilder.append("__kernel void " + m.getName() + "("); + final List<OpenCLArgDescriptor> args = getArgs(m); + + boolean first = true; + for (final OpenCLArgDescriptor arg : args) { + if (first) { + first = false; + } else { + sourceBuilder.append(","); + } + sourceBuilder.append("\n " + arg); + } + + sourceBuilder.append(")"); + final Kernel kernel = (Kernel) a; + sourceBuilder.append(kernel.value()); + kernelNameToArgsMap.put(m.getName(), args); + + } + } + } + } + + } + _source = sourceBuilder.toString(); + } else { + for (final Method m : _interface.getDeclaredMethods()) { + if (!isReservedInterfaceMethod(m)) { + final List<OpenCLArgDescriptor> args = getArgs(m); + kernelNameToArgsMap.put(m.getName(), args); + } + } + } + + final OpenCLProgram program = new OpenCLProgram(this, _source).createProgram(this); + + final Map<String, OpenCLKernel> map = new HashMap<String, OpenCLKernel>(); + for (final String name : kernelNameToArgsMap.keySet()) { + final OpenCLKernel kernel = OpenCLKernel.createKernel(program, name, kernelNameToArgsMap.get(name)); + //final OpenCLKernel kernel = new OpenCLKernel(program, name, kernelNameToArgsMap.get(name)); + if (kernel == null) { + throw new IllegalStateException("kernel is null"); + } + + map.put(name, kernel); + } + + final OpenCLInvocationHandler<T> invocationHandler = new OpenCLInvocationHandler<T>(program, map); + final T instance = (T) Proxy.newProxyInstance(OpenCLDevice.class.getClassLoader(), new Class[] { + _interface, + OpenCL.class + }, invocationHandler); + + return instance; + } + + public interface DeviceSelector{ + OpenCLDevice select(OpenCLDevice _device); + } + + public interface DeviceComparitor{ + OpenCLDevice select(OpenCLDevice _deviceLhs, OpenCLDevice _deviceRhs); + } + + /** List OpenCLDevices of a given TYPE, or all OpenCLDevices if type == null. */ + public static List<OpenCLDevice> listDevices(TYPE type) { + final OpenCLPlatform platform = new OpenCLPlatform(0, null, null, null); + final ArrayList<OpenCLDevice> results = new ArrayList<>(); + + for (final OpenCLPlatform p : platform.getOpenCLPlatforms()) { + for (final OpenCLDevice device : p.getOpenCLDevices()) { + if (type == null || device.getType() == type) { + results.add(device); + } + } + } + + return results; + } + + public static OpenCLDevice select(DeviceSelector _deviceSelector) { + OpenCLDevice device = null; + final OpenCLPlatform platform = new OpenCLPlatform(0, null, null, null); + + for (final OpenCLPlatform p : platform.getOpenCLPlatforms()) { + for (final OpenCLDevice d : p.getOpenCLDevices()) { + device = _deviceSelector.select(d); + if (device != null) { + break; + } + } + if (device != null) { + break; + } + } + + return (device); + } + + public static OpenCLDevice select(DeviceComparitor _deviceComparitor) { + OpenCLDevice device = null; + final OpenCLPlatform platform = new OpenCLPlatform(0, null, null, null); + + List<OpenCLPlatform> openCLPlatforms = platform.getOpenCLPlatforms(); + for (final OpenCLPlatform p : openCLPlatforms) { + List<OpenCLDevice> openCLDevices = p.getOpenCLDevices(); + for (final OpenCLDevice d : openCLDevices) { + if (device == null) { + device = d; + } else { + device = _deviceComparitor.select(device, d); + } + } + } + + return (device); + } + + public static OpenCLDevice select(DeviceComparitor _deviceComparitor, Device.TYPE _type) { + OpenCLDevice device = null; + final OpenCLPlatform platform = new OpenCLPlatform(0, null, null, null); + + for (final OpenCLPlatform p : platform.getOpenCLPlatforms()) { + for (final OpenCLDevice d : p.getOpenCLDevices()) { + if (d.getType() != _type) continue; + if (device == null) { + device = d; + } else { + device = _deviceComparitor.select(device, d); + } + } + } + + return (device); + } + + @Override public String toString() { + final StringBuilder s = new StringBuilder("{"); + boolean first = true; + for (final int workItemSize : maxWorkItemSize) { + if (first) { + first = false; + } else { + s.append(", "); + } + + s.append(workItemSize); + } + + s.append("}"); + + return ("Device " + deviceId + "\n vendor = " + getOpenCLPlatform().getVendor() + + "\n type:" + type + "\n maxComputeUnits=" + maxComputeUnits + "\n maxWorkItemDimensions=" + + maxWorkItemDimensions + "\n maxWorkItemSizes=" + s + "\n maxWorkWorkGroupSize=" + maxWorkGroupSize + + "\n globalMemSize=" + globalMemSize + "\n localMemSize=" + localMemSize); + } +} diff --git a/src/main/java/com/aparapi/device/package-info.java b/src/main/java/com/aparapi/device/package-info.java index fd8989ab369dba9cd3b0afdef0a73e8067cc7ce8..f853ab927ad4f4b5abdb50b6b83ffb21cbf302a5 100644 --- a/src/main/java/com/aparapi/device/package-info.java +++ b/src/main/java/com/aparapi/device/package-info.java @@ -1,34 +1,34 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Contains classes representing OpenCL-capable devices, and "virtual" (java) devices which execute kernels using java. - * - * <p>Various methods of {@link com.aparapi.device.Device} which selected devices of a particular type have been deprecated, - * as now the preferred mechanism for device selection is to rely on the {@link com.aparapi.internal.kernel.KernelManager} to - * select an appropriate device. Where a particular device is required to be used for a certain kernel, for such purposes as - * debugging or unit testing, this can be achieved by using - * {@link com.aparapi.internal.kernel.KernelManager#setKernelManager(com.aparapi.internal.kernel.KernelManager)} prior to - * invoking any Kernel executions, by overriding {@link com.aparapi.Kernel#isAllowDevice(com.aparapi.device.Device)} - * to veto/approve devices from the available devices for a given Kernel class, or (not recommended) by using - * {@link com.aparapi.internal.kernel.KernelManager#setPreferredDevices(com.aparapi.Kernel, java.util.LinkedHashSet)} to specify - * a particular device list for a given Kernel class. - * - * <p>In order to determine the Device which will be used to execute a particular Kernel, use {@link com.aparapi.Kernel#getTargetDevice()}. - * This can also be used immediately after execution to see on which device the kernel actually got executed (in case the execution failed - * and fell back to another device). - * - */ +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Contains classes representing OpenCL-capable devices, and "virtual" (java) devices which execute kernels using java. + * + * <p>Various methods of {@link com.aparapi.device.Device} which selected devices of a particular type have been deprecated, + * as now the preferred mechanism for device selection is to rely on the {@link com.aparapi.internal.kernel.KernelManager} to + * select an appropriate device. Where a particular device is required to be used for a certain kernel, for such purposes as + * debugging or unit testing, this can be achieved by using + * {@link com.aparapi.internal.kernel.KernelManager#setKernelManager(com.aparapi.internal.kernel.KernelManager)} prior to + * invoking any Kernel executions, by overriding {@link com.aparapi.Kernel#isAllowDevice(com.aparapi.device.Device)} + * to veto/approve devices from the available devices for a given Kernel class, or (not recommended) by using + * {@link com.aparapi.internal.kernel.KernelManager#setPreferredDevices(com.aparapi.Kernel, java.util.LinkedHashSet)} to specify + * a particular device list for a given Kernel class. + * + * <p>In order to determine the Device which will be used to execute a particular Kernel, use {@link com.aparapi.Kernel#getTargetDevice()}. + * This can also be used immediately after execution to see on which device the kernel actually got executed (in case the execution failed + * and fell back to another device). + * + */ package com.aparapi.device; \ No newline at end of file diff --git a/src/main/java/com/aparapi/exception/DeprecatedException.java b/src/main/java/com/aparapi/exception/DeprecatedException.java index 628e5377088b07beb901414516e6f32a6ceb5f4f..026f623a4df2ca398c55ff8efaf884800b2a37e4 100644 --- a/src/main/java/com/aparapi/exception/DeprecatedException.java +++ b/src/main/java/com/aparapi/exception/DeprecatedException.java @@ -1,62 +1,62 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.exception; - -import com.aparapi.internal.exception.AparapiException; - -@SuppressWarnings("serial") public class DeprecatedException extends AparapiException{ - - public DeprecatedException(String msg) { - super(msg); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.exception; + +import com.aparapi.internal.exception.AparapiException; + +@SuppressWarnings("serial") public class DeprecatedException extends AparapiException{ + + public DeprecatedException(String msg) { + super(msg); + } +} diff --git a/src/main/java/com/aparapi/exception/package-info.java b/src/main/java/com/aparapi/exception/package-info.java index 0f2873dfa3426accafd6ddee073516f7b6f5d4af..7dc60930284c10b85ca87a3885d964a78366d9c7 100644 --- a/src/main/java/com/aparapi/exception/package-info.java +++ b/src/main/java/com/aparapi/exception/package-info.java @@ -1,19 +1,19 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * - */ +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + */ package com.aparapi.exception; \ No newline at end of file diff --git a/src/main/java/com/aparapi/internal/annotation/DocMe.java b/src/main/java/com/aparapi/internal/annotation/DocMe.java index 054b79ae716f9299329ca8d2c1fd52cc4b7633b0..50749ec6b1be6213188aeb3b2a9f55b9fc2f453e 100644 --- a/src/main/java/com/aparapi/internal/annotation/DocMe.java +++ b/src/main/java/com/aparapi/internal/annotation/DocMe.java @@ -1,24 +1,24 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.annotation; - -/** - * Use this annotation to tag stuff that needs Java Doc added - * - * @author gfrost - */ -public @interface DocMe { -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.annotation; + +/** + * Use this annotation to tag stuff that needs Java Doc added + * + * @author gfrost + */ +public @interface DocMe { +} diff --git a/src/main/java/com/aparapi/internal/annotation/RemoveMe.java b/src/main/java/com/aparapi/internal/annotation/RemoveMe.java index 584693fee02b390e3f4616fe36287b80714a363b..682c65006bab09c3e771db52e36971d885bd9c4e 100644 --- a/src/main/java/com/aparapi/internal/annotation/RemoveMe.java +++ b/src/main/java/com/aparapi/internal/annotation/RemoveMe.java @@ -1,24 +1,24 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.annotation; - -/** - * Use this annotation to tag fields that we think need to be removed (method/field/var) - * - * @author gfrost - */ -public @interface RemoveMe { -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.annotation; + +/** + * Use this annotation to tag fields that we think need to be removed (method/field/var) + * + * @author gfrost + */ +public @interface RemoveMe { +} diff --git a/src/main/java/com/aparapi/internal/annotation/Unused.java b/src/main/java/com/aparapi/internal/annotation/Unused.java index fed55e49415f8edd0b2648342a4fca4afb7bec8d..1cc57837e733c991610cbae78629bc0ece288acb 100644 --- a/src/main/java/com/aparapi/internal/annotation/Unused.java +++ b/src/main/java/com/aparapi/internal/annotation/Unused.java @@ -1,28 +1,28 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.annotation; - -/** - * Used to tag unused features (methods/fields) - * <p> - * Do not rely on anything tagged as unused, it will probably be retracted/refactored - * - * @author gfrost - * - */ -public @interface Unused { - -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.annotation; + +/** + * Used to tag unused features (methods/fields) + * <p> + * Do not rely on anything tagged as unused, it will probably be retracted/refactored + * + * @author gfrost + * + */ +public @interface Unused { + +} diff --git a/src/main/java/com/aparapi/internal/annotation/UsedByJNICode.java b/src/main/java/com/aparapi/internal/annotation/UsedByJNICode.java index 829d2e5c6bf2c84f1010328edef8874473c60336..37533557446b09c6ca4987566da90860934234c5 100644 --- a/src/main/java/com/aparapi/internal/annotation/UsedByJNICode.java +++ b/src/main/java/com/aparapi/internal/annotation/UsedByJNICode.java @@ -1,23 +1,23 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.annotation; - -/** - * Be careful changing the name/type of this field as it is referenced from JNI code. - */ -public @interface UsedByJNICode { - -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.annotation; + +/** + * Be careful changing the name/type of this field as it is referenced from JNI code. + */ +public @interface UsedByJNICode { + +} diff --git a/src/main/java/com/aparapi/internal/exception/AparapiException.java b/src/main/java/com/aparapi/internal/exception/AparapiException.java index 05fd815116b45b0fb92f745d98a66c9bda562ecb..cbc6ef6ba54e7c295df03761d5780f453e56b319 100644 --- a/src/main/java/com/aparapi/internal/exception/AparapiException.java +++ b/src/main/java/com/aparapi/internal/exception/AparapiException.java @@ -1,77 +1,77 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.exception; - -/** - * We use <code>AparapiException</code> class and subclasses to wrap other - * <code>Exception</code> classes, mainly to allow differentiation between Aparapi specific issues at runtime. - * - * The class parser for example will throw a specific <code>ClassParseException</code> if any Aparapi unfriendly - * constructs are found. This allows us to <strong>fail fast</strong> during classfile parsing. - * - * @see com.aparapi.internal.exception.ClassParseException - * @see com.aparapi.internal.exception.CodeGenException - * - * @author gfrost - * - */ -@SuppressWarnings("serial") public class AparapiException extends Exception{ - - public AparapiException(String _msg) { - super(_msg); - } - - public AparapiException(Throwable _t) { - super(_t); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.exception; + +/** + * We use <code>AparapiException</code> class and subclasses to wrap other + * <code>Exception</code> classes, mainly to allow differentiation between Aparapi specific issues at runtime. + * + * The class parser for example will throw a specific <code>ClassParseException</code> if any Aparapi unfriendly + * constructs are found. This allows us to <strong>fail fast</strong> during classfile parsing. + * + * @see com.aparapi.internal.exception.ClassParseException + * @see com.aparapi.internal.exception.CodeGenException + * + * @author gfrost + * + */ +@SuppressWarnings("serial") public class AparapiException extends Exception{ + + public AparapiException(String _msg) { + super(_msg); + } + + public AparapiException(Throwable _t) { + super(_t); + } +} diff --git a/src/main/java/com/aparapi/internal/exception/ClassParseException.java b/src/main/java/com/aparapi/internal/exception/ClassParseException.java index 4114d7c5433b41a7adcaaa780b4d7e74b20e18ea..fcdac3f91a0026be3432880db31cb21592c635ef 100644 --- a/src/main/java/com/aparapi/internal/exception/ClassParseException.java +++ b/src/main/java/com/aparapi/internal/exception/ClassParseException.java @@ -1,148 +1,148 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.exception; - -import com.aparapi.internal.instruction.Instruction; - -/** - * We throw <code>ClassParseException</code>s (derived from <code>AparapiException</code>) if we encounter any Aparapi unfriendly - * constructs. This allows us to <strong>fail fast</strong>. - * - * @see com.aparapi.internal.exception.AparapiException - * - * @author gfrost - * - */ -@SuppressWarnings("serial") public class ClassParseException extends AparapiException{ - - public static enum TYPE { - NONE("none"), // - ARRAY_RETURN("We don't support areturn instructions"), // - PUTFIELD("We don't support putstatic instructions"), // - INVOKEINTERFACE("We don't support invokeinterface instructions"), // - GETSTATIC("We don't support getstatic instructions"), // - ATHROW("We don't support athrow instructions"), // - SYNCHRONIZE("We don't support monitorenter or monitorexit instructions"), // - NEW("We don't support new instructions"), // - ARRAYALIAS("We don't support copying refs in kernels"), // - SWITCH("We don't support lookupswitch or tableswitch instructions"), // - METHODARRAYARG("We don't support passing arrays as method args"), // - RECURSION("We don't support recursion"), // - UNSUPPORTEDBYTECODE("This bytecode is not supported"), // - OPERANDCONSUMERPRODUCERMISSMATCH("Detected an non-reducable operand consumer/producer mismatch"), // - BADGETTERTYPEMISMATCH("Getter return type does not match field var type"), // - BADGETTERNAMEMISMATCH("Getter name does not match fiels name"), // - BADGETTERNAMENOTFOUND("Getter not found"), // - BADSETTERTYPEMISMATCH("Setter arg type does not match field var type"), // - EXCEPTION("We don't support catch blocks"), // - ARRAYLOCALVARIABLE("Found an array local variable which assumes that we will alias a field array"), // - CONFUSINGBRANCHESPOSSIBLYCONTINUE("we don't support continue"), // - CONFUSINGBRANCHESPOSSIBLYBREAK("we don't support break"), // - OBJECTFIELDREFERENCE("Using java objects inside kernels is not supported"), // - OBJECTARRAYFIELDREFERENCE("Object array elements cannot contain"), // - OVERRIDENFIELD("Found overidden field"), // - LOCALARRAYLENGTHACCESS("Found array length access on local array. Might be a result of using ForEach()"), // - ACCESSEDOBJECTNONFINAL("Kernel array object member class must be final."), // - ACCESSEDOBJECTFIELDNAMECONFLICT("Conflicting fields found in class hierarchy"), // - ACCESSEDOBJECTONLYSUPPORTSSIMPLEPUTFIELD("We don't support putfield instructions beyond simple setters"), // - ACCESSEDOBJECTSETTERARRAY("Passing array arguments to Intrinsics in expression form is not supported"), // - MULTIDIMENSIONARRAYASSIGN("Can't assign to two dimension array"), // - MULTIDIMENSIONARRAYACCESS("Can't access through a two dimensional array"), // - MISSINGLOCALVARIABLETABLE("Method does not contain a local variable table (recompile with -g?)"), // - IMPROPERPRIVATENAMEMANGLING("Could not parse private array size from field name"); - - private String description; - - TYPE(final String _description) { - description = _description; - } - - public String getDescription() { - return (description); - } - }; - - private Instruction instruction; - - private TYPE type; - - public ClassParseException(final TYPE _type) { - super(_type.getDescription()); - type = _type; - instruction = null; - } - - public ClassParseException(final Instruction _instruction, final TYPE _type) { - super("@" + _instruction.getThisPC() + " " + _instruction.getByteCode() + " " + _type.getDescription()); - type = _type; - instruction = _instruction; - } - - public ClassParseException(final TYPE _type, final String _methodName) { - super("@" + _methodName + " " + _type.getDescription()); - type = _type; - instruction = null; - } - - public ClassParseException(final Throwable _t) { - super(_t); - } - - public Instruction getInstruction() { - return (instruction); - } - - public TYPE getType() { - return (type); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.exception; + +import com.aparapi.internal.instruction.Instruction; + +/** + * We throw <code>ClassParseException</code>s (derived from <code>AparapiException</code>) if we encounter any Aparapi unfriendly + * constructs. This allows us to <strong>fail fast</strong>. + * + * @see com.aparapi.internal.exception.AparapiException + * + * @author gfrost + * + */ +@SuppressWarnings("serial") public class ClassParseException extends AparapiException{ + + public static enum TYPE { + NONE("none"), // + ARRAY_RETURN("We don't support areturn instructions"), // + PUTFIELD("We don't support putstatic instructions"), // + INVOKEINTERFACE("We don't support invokeinterface instructions"), // + GETSTATIC("We don't support getstatic instructions"), // + ATHROW("We don't support athrow instructions"), // + SYNCHRONIZE("We don't support monitorenter or monitorexit instructions"), // + NEW("We don't support new instructions"), // + ARRAYALIAS("We don't support copying refs in kernels"), // + SWITCH("We don't support lookupswitch or tableswitch instructions"), // + METHODARRAYARG("We don't support passing arrays as method args"), // + RECURSION("We don't support recursion"), // + UNSUPPORTEDBYTECODE("This bytecode is not supported"), // + OPERANDCONSUMERPRODUCERMISSMATCH("Detected an non-reducable operand consumer/producer mismatch"), // + BADGETTERTYPEMISMATCH("Getter return type does not match field var type"), // + BADGETTERNAMEMISMATCH("Getter name does not match fiels name"), // + BADGETTERNAMENOTFOUND("Getter not found"), // + BADSETTERTYPEMISMATCH("Setter arg type does not match field var type"), // + EXCEPTION("We don't support catch blocks"), // + ARRAYLOCALVARIABLE("Found an array local variable which assumes that we will alias a field array"), // + CONFUSINGBRANCHESPOSSIBLYCONTINUE("we don't support continue"), // + CONFUSINGBRANCHESPOSSIBLYBREAK("we don't support break"), // + OBJECTFIELDREFERENCE("Using java objects inside kernels is not supported"), // + OBJECTARRAYFIELDREFERENCE("Object array elements cannot contain"), // + OVERRIDENFIELD("Found overidden field"), // + LOCALARRAYLENGTHACCESS("Found array length access on local array. Might be a result of using ForEach()"), // + ACCESSEDOBJECTNONFINAL("Kernel array object member class must be final."), // + ACCESSEDOBJECTFIELDNAMECONFLICT("Conflicting fields found in class hierarchy"), // + ACCESSEDOBJECTONLYSUPPORTSSIMPLEPUTFIELD("We don't support putfield instructions beyond simple setters"), // + ACCESSEDOBJECTSETTERARRAY("Passing array arguments to Intrinsics in expression form is not supported"), // + MULTIDIMENSIONARRAYASSIGN("Can't assign to two dimension array"), // + MULTIDIMENSIONARRAYACCESS("Can't access through a two dimensional array"), // + MISSINGLOCALVARIABLETABLE("Method does not contain a local variable table (recompile with -g?)"), // + IMPROPERPRIVATENAMEMANGLING("Could not parse private array size from field name"); + + private String description; + + TYPE(final String _description) { + description = _description; + } + + public String getDescription() { + return (description); + } + }; + + private Instruction instruction; + + private TYPE type; + + public ClassParseException(final TYPE _type) { + super(_type.getDescription()); + type = _type; + instruction = null; + } + + public ClassParseException(final Instruction _instruction, final TYPE _type) { + super("@" + _instruction.getThisPC() + " " + _instruction.getByteCode() + " " + _type.getDescription()); + type = _type; + instruction = _instruction; + } + + public ClassParseException(final TYPE _type, final String _methodName) { + super("@" + _methodName + " " + _type.getDescription()); + type = _type; + instruction = null; + } + + public ClassParseException(final Throwable _t) { + super(_t); + } + + public Instruction getInstruction() { + return (instruction); + } + + public TYPE getType() { + return (type); + } +} diff --git a/src/main/java/com/aparapi/internal/exception/CodeGenException.java b/src/main/java/com/aparapi/internal/exception/CodeGenException.java index e32cd0701ade6d96d8bd00fe83b24f9a24455b62..ffc492e1388797a7e4665ef25578ff045f8a3aee 100644 --- a/src/main/java/com/aparapi/internal/exception/CodeGenException.java +++ b/src/main/java/com/aparapi/internal/exception/CodeGenException.java @@ -1,64 +1,64 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.exception; - -@SuppressWarnings("serial") public class CodeGenException extends AparapiException{ - - public CodeGenException(String msg) { - super(msg); - } - - public CodeGenException(Throwable t) { - super(t); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.exception; + +@SuppressWarnings("serial") public class CodeGenException extends AparapiException{ + + public CodeGenException(String msg) { + super(msg); + } + + public CodeGenException(Throwable t) { + super(t); + } +} diff --git a/src/main/java/com/aparapi/internal/exception/RangeException.java b/src/main/java/com/aparapi/internal/exception/RangeException.java index 12c4fdbb1e752265801c2e8d53ee7b4c44d19a59..f8b8c757b88ba5fb39343398ba915a47ef64fa23 100644 --- a/src/main/java/com/aparapi/internal/exception/RangeException.java +++ b/src/main/java/com/aparapi/internal/exception/RangeException.java @@ -1,60 +1,60 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.exception; - -@SuppressWarnings("serial") public class RangeException extends AparapiException{ - - public RangeException(String msg) { - super(msg); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.exception; + +@SuppressWarnings("serial") public class RangeException extends AparapiException{ + + public RangeException(String msg) { + super(msg); + } +} diff --git a/src/main/java/com/aparapi/internal/instruction/BranchSet.java b/src/main/java/com/aparapi/internal/instruction/BranchSet.java index bdce4bfc92fc945e472b2199259debfef883ab33..a0437b557e196f4a365715e1efc50410545eff1e 100644 --- a/src/main/java/com/aparapi/internal/instruction/BranchSet.java +++ b/src/main/java/com/aparapi/internal/instruction/BranchSet.java @@ -1,424 +1,424 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.instruction; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import com.aparapi.internal.instruction.InstructionSet.Branch; -import com.aparapi.internal.instruction.InstructionSet.ConditionalBranch; - -/** - * Deals with the issue of recognizing that a sequence of bytecode branch instructions actually represent a single if/while with a logical expression. - * - * <p> - * A logical expressions such as - * <pre><code> - if (i>= 0 && i%2 == 0 && i<100){} - * </code></pre> - * gets translated into a sequence of bytecode level branches and targets. Which might look like the following. - * <pre><code> - a: if ? e + - b: if ? d |+ - c: if ? e ||+ - d: if ? out |v|+ - e: ... v v| - ... | - out: _instruction v - * </code></pre> - * We need an algorithm for recognizing the underlying logical expression. - * <p> - * Essentially, given a set of branches, get the longest sequential sequence including the input set which target each other or _target. - * - * Branches can legally branch to another in the valid set, or to the fall through of the last in the valid set or to _target - *<p> - * So an <pre>if(COND){IF_INSTRUCTIONS}else{ELSE_INSTUCTIONS}...</pre> will be -<pre><code> - branch[?? branch]*, instructions*,goto,instruction*,target -</code></pre> - * and <pre>if(COND){IF_INSTRUCTIONS}...</pre> will be :- -<code><pre> - branch[?? branch]*,instruction*,target -</pre></code> - * The psuedo code code the algorithm looks like this: -<code><pre> - int n=0; - while (exp.length >1){ - if (exp[n].target == exp[n+1].target){ #rule 1 - replace exp[n] and exp[n+1] with a single expression representing 'exp[n] || exp[n+1]' - n=0; - }else if (exp[n].target == exp[n+1].next){ #rule 2 - replace exp[n] and exp[n+1] with a single expression representing '!(exp[n]) && exp[n+1] - n=0; - }else{ #rule 3 - n++; - } - } - - result = !exp[0]; -</pre></code> - * @author gfrost - */ - -public class BranchSet { - /** - * Base abstract class used to hold information used to construct node tree for logical expressions. - * - * @see SimpleLogicalExpressionNode - * @see CompoundLogicalExpressionNode - * - * @author gfrost - * - */ - public static abstract class LogicalExpressionNode { - private LogicalExpressionNode next = null; - - private LogicalExpressionNode parent = null; - - public void setParent(LogicalExpressionNode _parent) { - parent = _parent; - } - - public abstract int getTarget(); - - public abstract int getFallThrough(); - - public abstract void invert(); - - public abstract LogicalExpressionNode cloneInverted(); - - public LogicalExpressionNode getRoot() { - if (parent != null) { - return (parent); - } else { - return (this); - } - } - - public LogicalExpressionNode getNext() { - return (next == null ? next : next.getRoot()); - } - - public void setNext(LogicalExpressionNode _next) { - next = _next == null ? _next : _next.getRoot(); - } - - public LogicalExpressionNode getParent() { - return (parent); - } - } - - /** - * A node in the expression tree representing a simple logical expression. - * - * For example <bold><code>(i<3)</code></bold> in the following would appear as a SimpleLogicalExpressionNode<br/> - * <pre><code> - * if (i<3){} - * </code></pre> - * - * @author gfrost - * - */ - public static class SimpleLogicalExpressionNode extends LogicalExpressionNode { - private final ConditionalBranch branch; - - private boolean invert; - - public SimpleLogicalExpressionNode(ConditionalBranch _branch) { - this(_branch, false); - } - - private SimpleLogicalExpressionNode(ConditionalBranch _branch, boolean _invert) { - branch = _branch; - invert = _invert; - } - - @Override - public int getTarget() { - return (getBranch().getTarget().getThisPC()); - } - - @Override - public void invert() { - invert = !invert; - } - - @Override - public LogicalExpressionNode cloneInverted() { - return new SimpleLogicalExpressionNode(branch, !invert); - } - - @Override - public int getFallThrough() { - return (getBranch().getNextPC().getThisPC()); - } - - public boolean isInvert() { - return (invert); - } - - public ConditionalBranch getBranch() { - return branch; - } - - @Override - public String toString() { - return invert ? ("!(" + getBranch() + ")") : getBranch().toString(); - } - } - - /** - * A node in the expression tree representing a simple logical expression. - * - * For example <bold><code>(i<3 || i>10)</code></bold> in the following would appear as a CompoundLogicalExpressionNode<br/> - * <pre><code> - * if (i<3 || i>10){} - * </code></pre> - * - * @author gfrost - * - */ - public static class CompoundLogicalExpressionNode extends LogicalExpressionNode { - private final LogicalExpressionNode lhs; - - private final LogicalExpressionNode rhs; - - private boolean and; - - private CompoundLogicalExpressionNode(boolean _and, LogicalExpressionNode _lhs, LogicalExpressionNode _rhs, - boolean applyInverts) { - lhs = _lhs; - and = _and; - rhs = _rhs; - setNext(_rhs.getNext()); - if (applyInverts) { - if (and) { - lhs.invert(); - // rhs.invert(); - } - } - rhs.setParent(this); - lhs.setParent(this); - } - - public CompoundLogicalExpressionNode(boolean _and, LogicalExpressionNode _lhs, LogicalExpressionNode _rhs) { - this(_and, _lhs, _rhs, true); - } - - @Override - public int getTarget() { - return (rhs.getTarget()); - } - - @Override - public void invert() { - and = !and; - lhs.invert(); - rhs.invert(); - } - - @Override - public LogicalExpressionNode cloneInverted() { - return new CompoundLogicalExpressionNode(!and, lhs.cloneInverted(), rhs.cloneInverted(), false); - } - - public boolean isAnd() { - return (and); - } - - @Override - public int getFallThrough() { - return (rhs.getFallThrough()); - } - - public LogicalExpressionNode getLhs() { - - return lhs; - } - - public LogicalExpressionNode getRhs() { - - return rhs; - } - - @Override - public String toString() { - return getLhs().toString() + " " + (isAnd() ? "&&" : "||") + " " + getRhs().toString(); - } - - } - - private final List<ConditionalBranch> set = new ArrayList<ConditionalBranch>(); - - private final Instruction fallThrough; - - private final Instruction target; - - private final Branch last; - - private Branch first; - - private LogicalExpressionNode logicalExpressionNode = null; - - /** - * We construct a branch set with the 'last' branch. It is assumed that all nodes prior to <code>_branch</code> are folded. - * - * This will walk backwards until it finds a non-branch or until it finds a branch that does not below to this set. - * - * @param _branch - */ - public BranchSet(Branch _branch) { - target = _branch.getTarget(); - last = _branch; - - final Set<Branch> expandedSet = new LinkedHashSet<Branch>(); - final Instruction fallThroughRoot = last.getNextExpr(); - fallThrough = fallThroughRoot == null ? last.getNextPC() : fallThroughRoot.getStartInstruction(); - first = last; - while ((first.getPrevExpr() != null) && first.getPrevExpr().isBranch() && first.getPrevExpr().asBranch().isConditional()) { - final Instruction prevBranchTarget = first.getPrevExpr().asBranch().getTarget(); - final Instruction prevBranchTargetRoot = prevBranchTarget.getRootExpr(); - if ((prevBranchTarget == target) || (prevBranchTarget == fallThrough) || expandedSet.contains(prevBranchTargetRoot)) { - expandedSet.add(first); - first = first.getPrevExpr().asBranch(); - } else { - break; - } - } - for (Instruction i = first; i != fallThroughRoot; i = i.getNextExpr()) { - set.add((ConditionalBranch) i.asBranch()); - ((ConditionalBranch) i.asBranch()).setBranchSet(this); - } - - // ConditionalBranch16 branches[] = set.toArray(new ConditionalBranch16[0]); - - LogicalExpressionNode end = null; - for (final ConditionalBranch cb : set) { - final SimpleLogicalExpressionNode sn = new SimpleLogicalExpressionNode(cb); - if (logicalExpressionNode == null) { - logicalExpressionNode = sn; - } else { - end.setNext(sn); - } - end = sn; - } - int count = 0; - while (logicalExpressionNode.next != null) { - if (++count > 20) { - throw new IllegalStateException("Sanity check, we seem to have >20 iterations collapsing logical expression"); - } - LogicalExpressionNode n = logicalExpressionNode; - LogicalExpressionNode prev = null; - int i = 0; - - while ((n != null) && (n.getNext() != null)) { - if ((n.getTarget() == n.getNext().getTarget()) || (n.getTarget() == n.getNext().getFallThrough())) { - LogicalExpressionNode newNode = null; - if (n.getTarget() == n.getNext().getTarget()) { - // lhs(n) and rhs(n.next) are branching to the same location so we replace (lhs ?? rhs) with (lhs || rhs) - // System.out.println("exp["+i+"] exp["+(i+1)+"] replaced by (exp["+i+"] || exp["+(i+1)+"])"); - newNode = new CompoundLogicalExpressionNode(false, n, n.getNext()); - } else if (n.getTarget() == n.getNext().getFallThrough()) { - // lhs(n) target and rhs(n.next) fallthrough are the same so we replace (lhs ?? rhs) with !(lhs && rhs) - // System.out.println("exp["+i+"] exp["+(i+1)+"] replaced by (!exp["+i+"] && exp["+(i+1)+"])"); - newNode = new CompoundLogicalExpressionNode(true, n, n.getNext()); - } - if (n == logicalExpressionNode) { - logicalExpressionNode = newNode; - } - if (prev != null) { - prev.setNext(newNode); - } - break; - } else { - prev = n; - n = n.getNext(); - i++; - } - } - } - } - - public List<ConditionalBranch> getBranches() { - return (set); - } - - public Branch getFirst() { - return (first); - } - - public Branch getLast() { - - return (last); - } - - public void unhook() { - for (final Branch b : set) { - b.unhook(); - } - } - - public Instruction getTarget() { - return (target); - } - - public Instruction getFallThrough() { - return (fallThrough); - } - - public LogicalExpressionNode getLogicalExpression() { - return (logicalExpressionNode); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.instruction; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import com.aparapi.internal.instruction.InstructionSet.Branch; +import com.aparapi.internal.instruction.InstructionSet.ConditionalBranch; + +/** + * Deals with the issue of recognizing that a sequence of bytecode branch instructions actually represent a single if/while with a logical expression. + * + * <p> + * A logical expressions such as + * <pre><code> + if (i>= 0 && i%2 == 0 && i<100){} + * </code></pre> + * gets translated into a sequence of bytecode level branches and targets. Which might look like the following. + * <pre><code> + a: if ? e + + b: if ? d |+ + c: if ? e ||+ + d: if ? out |v|+ + e: ... v v| + ... | + out: _instruction v + * </code></pre> + * We need an algorithm for recognizing the underlying logical expression. + * <p> + * Essentially, given a set of branches, get the longest sequential sequence including the input set which target each other or _target. + * + * Branches can legally branch to another in the valid set, or to the fall through of the last in the valid set or to _target + *<p> + * So an <pre>if(COND){IF_INSTRUCTIONS}else{ELSE_INSTUCTIONS}...</pre> will be +<pre><code> + branch[?? branch]*, instructions*,goto,instruction*,target +</code></pre> + * and <pre>if(COND){IF_INSTRUCTIONS}...</pre> will be :- +<code><pre> + branch[?? branch]*,instruction*,target +</pre></code> + * The psuedo code code the algorithm looks like this: +<code><pre> + int n=0; + while (exp.length >1){ + if (exp[n].target == exp[n+1].target){ #rule 1 + replace exp[n] and exp[n+1] with a single expression representing 'exp[n] || exp[n+1]' + n=0; + }else if (exp[n].target == exp[n+1].next){ #rule 2 + replace exp[n] and exp[n+1] with a single expression representing '!(exp[n]) && exp[n+1] + n=0; + }else{ #rule 3 + n++; + } + } + + result = !exp[0]; +</pre></code> + * @author gfrost + */ + +public class BranchSet { + /** + * Base abstract class used to hold information used to construct node tree for logical expressions. + * + * @see SimpleLogicalExpressionNode + * @see CompoundLogicalExpressionNode + * + * @author gfrost + * + */ + public static abstract class LogicalExpressionNode { + private LogicalExpressionNode next = null; + + private LogicalExpressionNode parent = null; + + public void setParent(LogicalExpressionNode _parent) { + parent = _parent; + } + + public abstract int getTarget(); + + public abstract int getFallThrough(); + + public abstract void invert(); + + public abstract LogicalExpressionNode cloneInverted(); + + public LogicalExpressionNode getRoot() { + if (parent != null) { + return (parent); + } else { + return (this); + } + } + + public LogicalExpressionNode getNext() { + return (next == null ? next : next.getRoot()); + } + + public void setNext(LogicalExpressionNode _next) { + next = _next == null ? _next : _next.getRoot(); + } + + public LogicalExpressionNode getParent() { + return (parent); + } + } + + /** + * A node in the expression tree representing a simple logical expression. + * + * For example <bold><code>(i<3)</code></bold> in the following would appear as a SimpleLogicalExpressionNode<br/> + * <pre><code> + * if (i<3){} + * </code></pre> + * + * @author gfrost + * + */ + public static class SimpleLogicalExpressionNode extends LogicalExpressionNode { + private final ConditionalBranch branch; + + private boolean invert; + + public SimpleLogicalExpressionNode(ConditionalBranch _branch) { + this(_branch, false); + } + + private SimpleLogicalExpressionNode(ConditionalBranch _branch, boolean _invert) { + branch = _branch; + invert = _invert; + } + + @Override + public int getTarget() { + return (getBranch().getTarget().getThisPC()); + } + + @Override + public void invert() { + invert = !invert; + } + + @Override + public LogicalExpressionNode cloneInverted() { + return new SimpleLogicalExpressionNode(branch, !invert); + } + + @Override + public int getFallThrough() { + return (getBranch().getNextPC().getThisPC()); + } + + public boolean isInvert() { + return (invert); + } + + public ConditionalBranch getBranch() { + return branch; + } + + @Override + public String toString() { + return invert ? ("!(" + getBranch() + ")") : getBranch().toString(); + } + } + + /** + * A node in the expression tree representing a simple logical expression. + * + * For example <bold><code>(i<3 || i>10)</code></bold> in the following would appear as a CompoundLogicalExpressionNode<br/> + * <pre><code> + * if (i<3 || i>10){} + * </code></pre> + * + * @author gfrost + * + */ + public static class CompoundLogicalExpressionNode extends LogicalExpressionNode { + private final LogicalExpressionNode lhs; + + private final LogicalExpressionNode rhs; + + private boolean and; + + private CompoundLogicalExpressionNode(boolean _and, LogicalExpressionNode _lhs, LogicalExpressionNode _rhs, + boolean applyInverts) { + lhs = _lhs; + and = _and; + rhs = _rhs; + setNext(_rhs.getNext()); + if (applyInverts) { + if (and) { + lhs.invert(); + // rhs.invert(); + } + } + rhs.setParent(this); + lhs.setParent(this); + } + + public CompoundLogicalExpressionNode(boolean _and, LogicalExpressionNode _lhs, LogicalExpressionNode _rhs) { + this(_and, _lhs, _rhs, true); + } + + @Override + public int getTarget() { + return (rhs.getTarget()); + } + + @Override + public void invert() { + and = !and; + lhs.invert(); + rhs.invert(); + } + + @Override + public LogicalExpressionNode cloneInverted() { + return new CompoundLogicalExpressionNode(!and, lhs.cloneInverted(), rhs.cloneInverted(), false); + } + + public boolean isAnd() { + return (and); + } + + @Override + public int getFallThrough() { + return (rhs.getFallThrough()); + } + + public LogicalExpressionNode getLhs() { + + return lhs; + } + + public LogicalExpressionNode getRhs() { + + return rhs; + } + + @Override + public String toString() { + return getLhs().toString() + " " + (isAnd() ? "&&" : "||") + " " + getRhs().toString(); + } + + } + + private final List<ConditionalBranch> set = new ArrayList<ConditionalBranch>(); + + private final Instruction fallThrough; + + private final Instruction target; + + private final Branch last; + + private Branch first; + + private LogicalExpressionNode logicalExpressionNode = null; + + /** + * We construct a branch set with the 'last' branch. It is assumed that all nodes prior to <code>_branch</code> are folded. + * + * This will walk backwards until it finds a non-branch or until it finds a branch that does not below to this set. + * + * @param _branch + */ + public BranchSet(Branch _branch) { + target = _branch.getTarget(); + last = _branch; + + final Set<Branch> expandedSet = new LinkedHashSet<Branch>(); + final Instruction fallThroughRoot = last.getNextExpr(); + fallThrough = fallThroughRoot == null ? last.getNextPC() : fallThroughRoot.getStartInstruction(); + first = last; + while ((first.getPrevExpr() != null) && first.getPrevExpr().isBranch() && first.getPrevExpr().asBranch().isConditional()) { + final Instruction prevBranchTarget = first.getPrevExpr().asBranch().getTarget(); + final Instruction prevBranchTargetRoot = prevBranchTarget.getRootExpr(); + if ((prevBranchTarget == target) || (prevBranchTarget == fallThrough) || expandedSet.contains(prevBranchTargetRoot)) { + expandedSet.add(first); + first = first.getPrevExpr().asBranch(); + } else { + break; + } + } + for (Instruction i = first; i != fallThroughRoot; i = i.getNextExpr()) { + set.add((ConditionalBranch) i.asBranch()); + ((ConditionalBranch) i.asBranch()).setBranchSet(this); + } + + // ConditionalBranch16 branches[] = set.toArray(new ConditionalBranch16[0]); + + LogicalExpressionNode end = null; + for (final ConditionalBranch cb : set) { + final SimpleLogicalExpressionNode sn = new SimpleLogicalExpressionNode(cb); + if (logicalExpressionNode == null) { + logicalExpressionNode = sn; + } else { + end.setNext(sn); + } + end = sn; + } + int count = 0; + while (logicalExpressionNode.next != null) { + if (++count > 20) { + throw new IllegalStateException("Sanity check, we seem to have >20 iterations collapsing logical expression"); + } + LogicalExpressionNode n = logicalExpressionNode; + LogicalExpressionNode prev = null; + int i = 0; + + while ((n != null) && (n.getNext() != null)) { + if ((n.getTarget() == n.getNext().getTarget()) || (n.getTarget() == n.getNext().getFallThrough())) { + LogicalExpressionNode newNode = null; + if (n.getTarget() == n.getNext().getTarget()) { + // lhs(n) and rhs(n.next) are branching to the same location so we replace (lhs ?? rhs) with (lhs || rhs) + // System.out.println("exp["+i+"] exp["+(i+1)+"] replaced by (exp["+i+"] || exp["+(i+1)+"])"); + newNode = new CompoundLogicalExpressionNode(false, n, n.getNext()); + } else if (n.getTarget() == n.getNext().getFallThrough()) { + // lhs(n) target and rhs(n.next) fallthrough are the same so we replace (lhs ?? rhs) with !(lhs && rhs) + // System.out.println("exp["+i+"] exp["+(i+1)+"] replaced by (!exp["+i+"] && exp["+(i+1)+"])"); + newNode = new CompoundLogicalExpressionNode(true, n, n.getNext()); + } + if (n == logicalExpressionNode) { + logicalExpressionNode = newNode; + } + if (prev != null) { + prev.setNext(newNode); + } + break; + } else { + prev = n; + n = n.getNext(); + i++; + } + } + } + } + + public List<ConditionalBranch> getBranches() { + return (set); + } + + public Branch getFirst() { + return (first); + } + + public Branch getLast() { + + return (last); + } + + public void unhook() { + for (final Branch b : set) { + b.unhook(); + } + } + + public Instruction getTarget() { + return (target); + } + + public Instruction getFallThrough() { + return (fallThrough); + } + + public LogicalExpressionNode getLogicalExpression() { + return (logicalExpressionNode); + } +} diff --git a/src/main/java/com/aparapi/internal/instruction/ExpressionList.java b/src/main/java/com/aparapi/internal/instruction/ExpressionList.java index c5c8413cf5f77b6e2c5e2f2f83c8849c1a03eec6..2aac1c00fd9cb9065bc95025d7d10407f8c3e396 100644 --- a/src/main/java/com/aparapi/internal/instruction/ExpressionList.java +++ b/src/main/java/com/aparapi/internal/instruction/ExpressionList.java @@ -1,988 +1,988 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.instruction; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.aparapi.Config; -import com.aparapi.internal.exception.ClassParseException; -import com.aparapi.internal.instruction.InstructionSet.AssignToLocalVariable; -import com.aparapi.internal.instruction.InstructionSet.Branch; -import com.aparapi.internal.instruction.InstructionSet.ByteCode; -import com.aparapi.internal.instruction.InstructionSet.CompositeArbitraryScopeInstruction; -import com.aparapi.internal.instruction.InstructionSet.CompositeInstruction; -import com.aparapi.internal.instruction.InstructionSet.ConditionalBranch; -import com.aparapi.internal.instruction.InstructionSet.FakeGoto; -import com.aparapi.internal.instruction.InstructionSet.Return; -import com.aparapi.internal.instruction.InstructionSet.UnconditionalBranch; -import com.aparapi.internal.model.MethodModel; -import com.aparapi.internal.model.ClassModel.LocalVariableTableEntry; -import com.aparapi.internal.model.ClassModel.LocalVariableInfo; - -/** - * Essentially a glorified linked list of Instructions plus some additional state to allow us to transform sequences. - * - * ExpressionLists do have the notion of a parent which allows us to clone an existing parent, allow transformations - * and then possibly commit or abort the transformations at will. - * @author gfrost - * - */ -public class ExpressionList{ - - private static Logger logger = Logger.getLogger(Config.getLoggerName()); - - private final MethodModel methodModel; - - private final ExpressionList parent; - - private Instruction head; - - private Instruction tail; - - private final Instruction instruction; - - private ExpressionList(MethodModel _methodModel, ExpressionList _parent, Instruction _instruction) { - - methodModel = _methodModel; - parent = _parent; - instruction = _instruction; - if (parent != null) { - head = parent.head; - tail = parent.tail; - } - if (instruction != null) { - tail = _instruction.getPrevExpr(); - tail.setNextExpr(null); - _instruction.setPrevExpr(null); - } - } - - public ExpressionList(MethodModel _methodModel) { - this(_methodModel, null, null); - } - - /** - * Determine whether the sequence of instructions from _start to _extent is free of branches which extend beyond _extent. - * - * As a side effect, if we find a possible branch it is likely a break or continue so we mark the conditional as such. - * - * @param _start - * @param _extent - * @return - */ - public boolean doesNotContainContinueOrBreak(Instruction _start, Instruction _extent) { - boolean ok = true; - boolean breakOrContinue = false; - for (Instruction i = _start; i != null; i = i.getNextExpr()) { - if (i.isBranch()) { - if (i.asBranch().isForwardUnconditional() && i.asBranch().getTarget().isAfter(_extent)) { - breakOrContinue = true; - } else { - ok = false; - break; - } - } - } - if (ok) { - if (breakOrContinue) { - for (Instruction i = _start; i != null; i = i.getNextExpr()) { - if (i.isBranch() && i.asBranch().isForwardUnconditional() && i.asBranch().getTarget().isAfter(_extent)) { - i.asBranch().setBreakOrContinue(true); - } - } - } - } - return (ok); - } - - public boolean doesNotContainCompositeOrBranch(Instruction _start, Instruction _exclusiveEnd) { - boolean ok = true; - for (Instruction i = _start; (i != null) && (i != _exclusiveEnd); i = i.getNextExpr()) { - if (!(i instanceof CompositeInstruction) && (i.isBranch())) { - ok = false; - break; - } - } - return (ok); - } - - public void unwind() { - if (parent != null) { - if (instruction != null) { - tail.setNextExpr(instruction); - instruction.setPrevExpr(tail); - parent.head = head; - } else { - parent.head = head; - parent.tail = tail; - } - } - } - - /** - * [1] [2] [3] [4] - * - * Note that passing null here essentially deletes the existing expression list and returns the expression - * - * @param _newTail - * @return - */ - - public Instruction createList(final Instruction _newTail) { - Instruction childExprHead = null; - if (_newTail == null) { - childExprHead = head; - tail = head = null; - } else { - childExprHead = _newTail.getNextExpr(); - tail = _newTail; - _newTail.setNextExpr(null); - if (childExprHead != null) { - childExprHead.setPrevExpr(null); - } - - } - return (childExprHead); - } - - /** - * Add this instruction to the end of the list. - * - * @param _instruction - * @return The instruction we added - */ - - public Instruction add(Instruction _instruction) { - - if (head == null) { - head = _instruction; - } else { - _instruction.setPrevExpr(tail); - tail.setNextExpr(_instruction); - - } - - tail = _instruction; - logger.log(Level.FINE, "After PUSH of " + _instruction + " tail=" + tail); - return (tail); - } - - /** - * Insert the given instruction (_newone) between the existing entries (_prev and _next). - * @param _prev - * @param _next - * @param _newOne - */ - public void insertBetween(Instruction _prev, Instruction _next, Instruction _newOne) { - _newOne.setNextExpr(null); - _newOne.setPrevExpr(null); - if (_prev == null) { - // this is the new head - if (_next == null) { - head = tail = _newOne; - } else { - _newOne.setNextExpr(head); - head.setPrevExpr(_newOne); - head = _newOne; - } - } else if (_next == null) { - _newOne.setPrevExpr(tail); - tail.setNextExpr(_newOne); - tail = _newOne; - } else { - _newOne.setNextExpr(_prev.getNextExpr()); - _newOne.setPrevExpr(_next.getPrevExpr()); - _prev.setNextExpr(_newOne); - _next.setPrevExpr(_newOne); - } - - } - - /** - * Inclusive replace between _head and _tail with _newOne. - * - * <pre> - * | | --> | | ---> ... ---> | | ---> | | - * | prev | | _head | | _tail | | next | - * | | <-- | | <--- ... <----| | <--- | | - * </pre> - * To - * <pre> - * | | --> | | ---> | | - * | prev | | _newOne | | next | - * | | <-- | | <--- | | - * </pre> - */ - - public void replaceInclusive(Instruction _head, Instruction _tail, Instruction _newOne) { - _newOne.setNextExpr(null); - _newOne.setPrevExpr(null); - final Instruction prevHead = _head.getPrevExpr(); - if (_tail == null) { - // this is the new tail - _newOne.setPrevExpr(prevHead); - prevHead.setNextExpr(_newOne); - tail = _newOne; - } else { - final Instruction tailNext = _tail.getNextExpr(); - if (prevHead == null) { - // this is the new head - if (tailNext == null) { - head = tail = _newOne; - } else { - _newOne.setNextExpr(head); - head.setPrevExpr(_newOne); - head = _newOne; - } - } else if (tailNext == null) { - _newOne.setPrevExpr(prevHead); - prevHead.setNextExpr(_newOne); - tail = _newOne; - _head.setPrevExpr(null); - } else { - _newOne.setNextExpr(tailNext); - _newOne.setPrevExpr(prevHead); - prevHead.setNextExpr(_newOne); - tailNext.setPrevExpr(_newOne); - - } - _tail.setNextExpr(null); - _head.setPrevExpr(null); - } - - } - - /** - * Fold headTail.tail into valid composites - * - * <pre> - * if(??){then}... - * ?? ?> [THEN] ... - * --------> - * - * if (??){THEN}else{ELSE}... - * - * ?? ?> [THEN] >> [ELSE] ... - * ------------> - * --------> - * - * sun for (INIT,??,DELTA){BODY} ... - * - * [INIT] ?? ?> [BODY] [DELTA] << ... - * ------------------> - * <------------------- - * - * sun for (,??,DELTA){BODY} ... - * - * ?? ?> [BODY] [DELTA] << ... - * ------------------> - * <------------------- - * - * sun while (?){l} ... - * - * ?? ?> [BODY] << ... - * -----------> - * <------------ - * - * eclipse for (INIT,??,DELTA){BODY} ... - * [INIT] >> [BODY] [DELTA] ?? ?< ... - * ----------------> - * <----------------- - * - * eclipse for (,??,DELTA){BODY} ... - * >> [BODY] [DELTA] ?? ?< ... - * ---------------> - * <----------------- - * - * eclipse while (??){BODY} ... - * >> [BODY] ?? ?< ... - * --------> - * <---------- - * - * eclipe if (?1) { while (?2) {BODY} } else {ELSE} ... - * ?1 ?> >> [BODY] ?2 ?< >> [ELSE] ... - * ---------> - * <--------- - * ---------------------> - * --------> - * - * sun for (,?1,DELTA){ if (?2) { THEN break; } BODY} ... - * - * ?1 ?> ?2 ?> [THEN] >> [BODY] [DELTA] << ... - * -----------> - * ----------------------------------> - * ------------------> - * <------------------------------------ - * - * sun for (,?1,DELTA){ if (?2) { THEN continue; } BODY} ... - * - * ?1 ?> ?2 ?> THEN >> [BODY] [DELTA] << ... - * ---------> - * --------> - * --------------------------------> - * <---------------------------------- - * - * Some exceptions based on sun javac optimizations - * - * if (?1){ if (?2){THEN} }else{ ELSE } ... - * One might expect - * ?1 ?> ?2 ?> [THEN] >> [ELSE] ... - * -----------------> - * -------->! - * -------------> - * However the conditional branch to the unconditional (!) is optimized away and instead the unconditional inverted and extended - * - * ?1 ?> ?2 ?> [THEN] >> [ELSE] ... - * -----------------> - * --------*---------> - * - * sun if (?1) { while (?2) {l} } else {e} ... - * One might expect - * ?1 ?> ?2 ?> [BODY] << >> [ELSE] ... - * -------------------> - * ----------->! - * <---------- - * --------> - * - * However as above the conditional branch to the unconditional (!) can be optimized away and the conditional inverted and extended - * ?1 ?> ?2 ?> [BODY] << >> [ELSE] ... - * --------------------> - * -----------*---------> - * <----------- - * - * However we can also now remove the forward unconditional completely as it is unreachable - * ?1 ?> ?2 ?> [BODY] << [ELSE] ... - * -----------------> - * ------------------> - * <----------- - * - * sun while(?1){if (?2) {THEN} else {ELSE} } ... - * One might expect - * ?1 ?> ?2 ?> [BODY] >> [ELSE] << ... - * --------------------------> - * <--------------------- - * ----------> - * ------->! - * - * However the unconditional branch to the unconditional backbranch (!) can be optimized away and the unconditional wrapped back directly to the loop control head - * ?1 ?> ?2 ?> [BODY] << [ELSE] << ... - * --------------------------> - * <--------------------- - * ----------> - * <----------- - - * </pre> - * @param _instruction - * @throws ClassParseException - */ - public boolean foldComposite(final Instruction _instruction) throws ClassParseException { - boolean handled = false; - try { - - if (logger.isLoggable(Level.FINE)) { - System.out.println("foldComposite: curr = " + _instruction); - System.out.println(dumpDiagram(_instruction)); - // System.out.println(dumpDiagram(null, _instruction)); - } - if (_instruction.isForwardBranchTarget() || ((tail != null) && tail.isBranch() && tail.asBranch().isReverseConditional())) { - while (_instruction.isForwardBranchTarget() - || ((tail != null) && tail.isBranch() && tail.asBranch().isReverseConditional())) { - if (logger.isLoggable(Level.FINE)) { - System.out.println(dumpDiagram(_instruction)); - - } - handled = false; - - if ((tail != null) && tail.isBranch() && tail.asBranch().isReverseConditional()) { - /** - * This looks like an eclipse style for/while loop or possibly a do{}while() - * <pre> - * eclipse for (INIT,??,DELTA){BODY} ... - * [INIT] >> [BODY] [DELTA] ?? ?< ... - * ----------------> - * <----------------- - * - * eclipse for (,??,DELTA){BODY} ... - * >> [BODY] [DELTA] ?? ?< ... - * ---------------> - * <----------------- - * - * do {BODY} while(??) - * [BODY] ?? ?< ... - * <----------- - * - * eclipse while (??){BODY} ... - * >> [BODY] ?? ?< ... - * --------> - * <---------- - * </pre> - **/ - final BranchSet branchSet = ((ConditionalBranch) tail.asBranch()).getOrCreateBranchSet(); - Instruction loopTop = branchSet.getTarget().getRootExpr(); - final Instruction beginingOfBranch = branchSet.getFirst(); - - final Instruction startOfBeginningOfBranch = beginingOfBranch.getStartInstruction(); - // empty loops sometimes look like eclipse loops! - if (startOfBeginningOfBranch == loopTop) { - - loopTop = loopTop.getPrevExpr(); - if (loopTop instanceof AssignToLocalVariable) { - final LocalVariableInfo localVariableInfo = ((AssignToLocalVariable) loopTop).getLocalVariableInfo(); - if ((localVariableInfo.getStart() == loopTop.getNextExpr().getStartPC()) - && (localVariableInfo.getEnd() == _instruction.getThisPC())) { - loopTop = loopTop.getPrevExpr(); // back up over the initialization - } - } - addAsComposites(ByteCode.COMPOSITE_EMPTY_LOOP, loopTop, branchSet); - handled = true; - } else { - - if ((loopTop.getPrevExpr() != null) && loopTop.getPrevExpr().isBranch() - && loopTop.getPrevExpr().asBranch().isForwardUnconditional()) { - if (doesNotContainCompositeOrBranch(branchSet.getTarget().getRootExpr(), branchSet.getFirst().getPrevExpr())) { - branchSet.unhook(); - loopTop.getPrevExpr().asBranch().unhook(); - loopTop = loopTop.getPrevExpr(); - // looptop == the unconditional? - loopTop = loopTop.getPrevExpr(); - if (loopTop instanceof AssignToLocalVariable) { - final LocalVariableInfo localVariableInfo = ((AssignToLocalVariable) loopTop).getLocalVariableInfo(); - if ((localVariableInfo.getStart() == loopTop.getNextExpr().getStartPC()) - && (localVariableInfo.getEnd() == _instruction.getThisPC())) { - loopTop = loopTop.getPrevExpr(); // back up over the initialization - } - } - addAsComposites(ByteCode.COMPOSITE_FOR_ECLIPSE, loopTop, branchSet); - handled = true; - } - } - if (!handled) { - // do{}while()_ do not require any previous instruction - if (loopTop.getPrevExpr() == null) { - throw new IllegalStateException("might be a dowhile with no provious expression"); - - } else if (!(loopTop.getPrevExpr().isBranch() && loopTop.getPrevExpr().asBranch().isForwardUnconditional())) { - if (doesNotContainCompositeOrBranch(branchSet.getTarget().getRootExpr(), branchSet.getFirst() - .getPrevExpr())) { - loopTop = loopTop.getPrevExpr(); - branchSet.unhook(); - addAsComposites(ByteCode.COMPOSITE_DO_WHILE, loopTop, branchSet); - handled = true; - } - } else { - throw new IllegalStateException("might be mistaken for a do while!"); - } - } - } - } - if (!handled && _instruction.isForwardConditionalBranchTarget() && tail.isBranch() - && tail.asBranch().isReverseUnconditional()) { - - /** - * This is s sun style loop - * <pre> - * sun for (INIT,??,DELTA){BODY} ... - * - * [INIT] ?? ?> [BODY] [DELTA] << ... - * ------------------> - * <------------------- - * - * sun for (,??,DELTA){BODY} ... - * - * ?? ?> [BODY] [DELTA] << ... - * ------------------> - * <------------------- - * - * sun while (?){l} ... - * - * ?? ?> [BODY] << ... - * -----------> - * <------------ - * - *</pre> - */ - final ConditionalBranch lastForwardConditional = _instruction.getForwardConditionalBranches().getLast(); - final BranchSet branchSet = lastForwardConditional.getOrCreateBranchSet(); - final Branch reverseGoto = tail.asBranch(); - final Instruction loopBackTarget = reverseGoto.getTarget(); - if (loopBackTarget.getReverseUnconditionalBranches().size() > 1) { - throw new ClassParseException(ClassParseException.TYPE.CONFUSINGBRANCHESPOSSIBLYCONTINUE); - } - if (_instruction.isForwardUnconditionalBranchTarget()) { - /** - * Check if we have a break - * <pre> - * ?? ?> [BODY] ?1 ?> >> [BODY] << ... - * --------------------------> - * ----> - * -----------> - * <---------------------------- - * - *</pre> - */ - final Branch lastForwardUnconditional = _instruction.getForwardUnconditionalBranches().getLast(); - if ((lastForwardUnconditional != null) && lastForwardUnconditional.isAfter(lastForwardConditional)) { - throw new ClassParseException(ClassParseException.TYPE.CONFUSINGBRANCHESPOSSIBLYBREAK); - } - } - if (loopBackTarget != branchSet.getFirst().getStartInstruction()) { - /** - * we may have a if(?1){while(?2){}}else{...} where the else goto has been optimized away. - * <pre> - * One might expect - * ?1 ?> ?2 ?> [BODY] << >> [ELSE] ... - * -------------------> - * ----------->! - * <---------- - * --------> - * - * However as above the conditional branch to the unconditional (!) can be optimized away and the conditional inverted and extended - * ?1 ?> ?2 ?> [BODY] << >> [ELSE] ... - * --------------------> - * -----------*---------> - * <----------- - * - * However we can also now remove the forward unconditional completely as it is unreachable - * ?1 ?> ?2 ?> [BODY] << [ELSE] ... - * -----------------> - * ------------------> - * <----------- - * - * </pre> - */ - - final Instruction loopbackTargetRoot = loopBackTarget.getRootExpr(); - if (loopbackTargetRoot.isBranch() && loopbackTargetRoot.asBranch().isConditional()) { - final ConditionalBranch topOfRealLoop = (ConditionalBranch) loopbackTargetRoot.asBranch(); - BranchSet extentBranchSet = topOfRealLoop.getBranchSet(); - if (topOfRealLoop.getBranchSet() == null) { - extentBranchSet = topOfRealLoop.findEndOfConditionalBranchSet(_instruction.getNextPC()) - .getOrCreateBranchSet(); - } - // We believe that this extendBranchSet is the real top of the while. - if (doesNotContainCompositeOrBranch(extentBranchSet.getLast().getNextExpr(), reverseGoto)) { - - Instruction loopTop = topOfRealLoop.getPrevExpr(); - if (loopTop instanceof AssignToLocalVariable) { - final LocalVariableInfo localVariableInfo = ((AssignToLocalVariable) loopTop).getLocalVariableInfo(); - if ((localVariableInfo.getStart() == loopTop.getNextExpr().getStartPC()) - && (localVariableInfo.getEnd() == _instruction.getThisPC())) { - loopTop = loopTop.getPrevExpr(); // back up over the initialization - } - } - extentBranchSet.unhook(); - - addAsComposites(ByteCode.COMPOSITE_FOR_SUN, loopTop, extentBranchSet); - final UnconditionalBranch fakeGoto = new FakeGoto(methodModel, extentBranchSet.getLast().getTarget()); - - add(fakeGoto); - extentBranchSet.getLast().getTarget().addBranchTarget(fakeGoto); - - handled = true; - } - } - } else { - /** - * Just a normal sun style loop - */ - if (doesNotContainCompositeOrBranch(branchSet.getLast().getNextExpr(), reverseGoto)) { - Instruction loopTop = reverseGoto.getTarget().getRootExpr().getPrevExpr(); - - if (logger.isLoggable(Level.FINEST)) { - Instruction next = branchSet.getFirst().getNextExpr(); - System.out.println("### for/while candidate exprs: " + branchSet.getFirst()); - while (next != null) { - System.out.println("### expr = " + next); - next = next.getNextExpr(); - } - } - - if (loopTop instanceof AssignToLocalVariable) { - final LocalVariableInfo localVariableInfo = ((AssignToLocalVariable) loopTop).getLocalVariableInfo(); - if ((localVariableInfo.getStart() == loopTop.getNextExpr().getStartPC()) - && (localVariableInfo.getEnd() == _instruction.getThisPC())) { - loopTop = loopTop.getPrevExpr(); // back up over the initialization - - } - } - branchSet.unhook(); - - // If there is an inner scope, it is likely that the loop counter var - // is modified using an inner scope variable so use while rather than for - if (reverseGoto.getPrevExpr() instanceof CompositeArbitraryScopeInstruction) { - addAsComposites(ByteCode.COMPOSITE_WHILE, loopTop, branchSet); - } else { - addAsComposites(ByteCode.COMPOSITE_FOR_SUN, loopTop, branchSet); - } - handled = true; - } - - } - } - if (!handled && !tail.isForwardBranch() && _instruction.isForwardConditionalBranchTarget()) { - /** - * This an if(exp) - *<pre> * - * if(??){then}... - * ?? ?> [THEN] ... - * --------> - * - *</pre> - */ - final ConditionalBranch lastForwardConditional = _instruction.getForwardConditionalBranches().getLast(); - final BranchSet branchSet = lastForwardConditional.getOrCreateBranchSet(); - if (doesNotContainContinueOrBreak(branchSet.getLast().getNextExpr(), _instruction)) { - branchSet.unhook(); - addAsComposites(ByteCode.COMPOSITE_IF, branchSet.getFirst().getPrevExpr(), branchSet); - handled = true; - } - } - if (!handled && !tail.isForwardBranch() && _instruction.isForwardUnconditionalBranchTarget()) { - - final LinkedList<Branch> forwardUnconditionalBranches = _instruction.getForwardUnconditionalBranches(); - - final Branch lastForwardUnconditional = forwardUnconditionalBranches.getLast(); - final Instruction afterGoto = lastForwardUnconditional.getNextExpr(); - if (afterGoto.getStartInstruction().isForwardConditionalBranchTarget()) { - final LinkedList<ConditionalBranch> forwardConditionalBranches = afterGoto.getStartInstruction() - .getForwardConditionalBranches(); - final ConditionalBranch lastForwardConditional = forwardConditionalBranches.getLast(); - final BranchSet branchSet = lastForwardConditional.getOrCreateBranchSet(); - - if (doesNotContainCompositeOrBranch(branchSet.getLast().getNextExpr(), lastForwardUnconditional)) { - if (doesNotContainContinueOrBreak(afterGoto.getNextExpr(), _instruction)) { - branchSet.unhook(); - lastForwardUnconditional.unhook(); - addAsComposites(ByteCode.COMPOSITE_IF_ELSE, branchSet.getFirst().getPrevExpr(), branchSet); - handled = true; - } - } else { - //then not clean. - final ExpressionList newHeadTail = new ExpressionList(methodModel, this, lastForwardUnconditional); - handled = newHeadTail.foldComposite(lastForwardUnconditional.getStartInstruction()); - newHeadTail.unwind(); - // handled = foldCompositeRecurse(lastForwardUnconditional); - if (!handled && (forwardUnconditionalBranches.size() > 1)) { - // BI AI AE BE - // ?> ?> .. >> .. >> C S - // ?---------------------->22 - // ?---------->18 - // +-------------->31 - // +------>31 - // Javac sometimes performs the above optimization. Basically the GOTO for the inner IFELSE(AI,AE) instead of targeting the GOTO - // from the outer IFELSE(B1,BE) so instead of AE->BE->... we have AE-->... - // - // So given more than one target we retreat up the list of unconditionals until we find a clean one treating the previously visited GOTO - // as a possible end - - for (int i = forwardUnconditionalBranches.size(); i > 1; i--) { - final Branch thisGoto = forwardUnconditionalBranches.get(i - 1); - final Branch elseGoto = forwardUnconditionalBranches.get(i - 2); - final Instruction afterElseGoto = elseGoto.getNextExpr(); - if (afterElseGoto.getStartInstruction().isConditionalBranchTarget()) { - final BranchSet elseBranchSet = afterElseGoto.getStartInstruction() - .getForwardConditionalBranches().getLast().getOrCreateBranchSet(); - if (doesNotContainCompositeOrBranch(elseBranchSet.getLast().getNextExpr(), elseGoto)) { - if (doesNotContainCompositeOrBranch(afterElseGoto.getNextExpr(), thisGoto)) { - if (logger.isLoggable(Level.FINE)) { - System.out.println(dumpDiagram(_instruction)); - } - elseBranchSet.unhook(); - elseGoto.unhook(); - if (logger.isLoggable(Level.FINE)) { - System.out.println(dumpDiagram(_instruction)); - - } - - final CompositeInstruction composite = CompositeInstruction.create( - ByteCode.COMPOSITE_IF_ELSE, methodModel, elseBranchSet.getFirst(), thisGoto, - elseBranchSet); - replaceInclusive(elseBranchSet.getFirst(), thisGoto.getPrevExpr(), composite); - - handled = true; - - break; - } - } - } - - } - - } - } - - } - - } - if (!handled && !tail.isForwardBranch() && _instruction.isForwardConditionalBranchTarget() - && _instruction.isForwardUnconditionalBranchTarget()) { - // here we have multiple composites ending at the same point - - final Branch lastForwardUnconditional = _instruction.getForwardUnconditionalBranches().getLast(); - final ConditionalBranch lastForwardConditional = _instruction.getStartInstruction() - .getForwardConditionalBranches().getLast(); - // we will clip the tail and see if recursing helps - - if (lastForwardConditional.getTarget().isAfter(lastForwardUnconditional)) { - - lastForwardConditional.retarget(lastForwardUnconditional); - - final ExpressionList newHeadTail = new ExpressionList(methodModel, this, lastForwardUnconditional); - handled = newHeadTail.foldComposite(lastForwardUnconditional.getStartInstruction()); - newHeadTail.unwind(); - - } - - } - if (!handled) { - break; - } - } - - } else { - - // might be end of arbitrary scope - final LocalVariableTableEntry<LocalVariableInfo> localVariableTable = methodModel.getMethod() - .getLocalVariableTableEntry(); - int startPc = Short.MAX_VALUE; - - for (final LocalVariableInfo localVariableInfo : localVariableTable) { - if (localVariableInfo.getEnd() == _instruction.getThisPC()) { - logger.fine(localVariableInfo.getVariableName() + " scope " + localVariableInfo.getStart() + " ," - + localVariableInfo.getEnd()); - if (localVariableInfo.getStart() < startPc) { - startPc = localVariableInfo.getStart(); - } - } - } - if (startPc < Short.MAX_VALUE) { - logger.fine("Scope block from " + startPc + " to " + (tail.getThisPC() + tail.getLength())); - for (Instruction i = head; i != null; i = i.getNextPC()) { - if (i.getThisPC() == startPc) { - final Instruction startInstruction = i.getRootExpr().getPrevExpr(); - logger.fine("Start = " + startInstruction); - - addAsComposites(ByteCode.COMPOSITE_ARBITRARY_SCOPE, startInstruction.getPrevExpr(), null); - handled = true; - break; - } - } - - } - - } - - if (Config.instructionListener != null) { - Config.instructionListener.showAndTell("after folding", head, _instruction); - } - - } catch (final ClassParseException _classParseException) { - throw new ClassParseException(_classParseException); - } catch (final Throwable t) { - throw new ClassParseException(t); - - } - return (handled); - } - - private void addAsComposites(ByteCode _byteCode, Instruction _start, BranchSet _branchSet) { - final Instruction childTail = tail; - final Instruction childHead = createList(_start); - final CompositeInstruction composite = CompositeInstruction.create(_byteCode, methodModel, childHead, childTail, _branchSet); - add(composite); - } - - /** - * Aids debugging. Creates a diagrammatic form of the roots (+ tail instruction) so that we can analyze control flow. - * <pre> - * I I I C C I U I U[I]I - * |---------->1 - * |---->1 - * |------>2 - * |-->2 - * </pre> - * @param _cursor The instruction we are looking at - * @param _instruction The instruction we are considering adding (may be null) - * @return - */ - public String dumpDiagram(Instruction _instruction) { - final StringBuilder sb = new StringBuilder(); - final List<Instruction> list = new ArrayList<Instruction>(); - - for (Instruction i = head; i != null; i = i.getNextExpr()) { - list.add(i); - } - - for (Instruction i = _instruction; i != null; i = i.getNextPC()) { - list.add(i); - } - - final Instruction[] array = list.toArray(new Instruction[0]); - boolean lastWasCursor = false; - - final List<Branch> branches = new ArrayList<Branch>(); - for (final Instruction i : list) { - sb.append(String.format(" %3d", i.getStartPC())); - } - - sb.append("\n"); - for (final Instruction i : list) { - sb.append(String.format(" %3d", i.getThisPC())); - } - - sb.append("\n"); - for (final Instruction i : list) { - - if (i == _instruction) { - sb.append(" ["); - lastWasCursor = true; - } else { - if (lastWasCursor) { - sb.append("] "); - lastWasCursor = false; - } else { - sb.append(" "); - } - } - if (i.isBranch() && i.asBranch().isConditional()) { - branches.add(i.asBranch()); - - if (i.asBranch().isForward()) { - sb.append("?>"); - - } else { - sb.append("?<"); - } - } else if (i.isBranch() && i.asBranch().isUnconditional()) { - branches.add(i.asBranch()); - if (i.asBranch().isForward()) { - sb.append(">>"); - } else { - sb.append("<<"); - } - } else if (i instanceof CompositeInstruction) { - sb.append(" C"); - } else if (i instanceof Return) { - - sb.append(" R"); - // } else if (i instanceof AssignToLocalVariable) { - // sb.append(" S"); - } else { - sb.append(".."); - } - } - - if (lastWasCursor) { - sb.append("] "); - } else { - sb.append(" "); - } - - for (final Branch b : branches) { - sb.append("\n "); - if (b.isForward()) { - for (int i = 0; i < array.length; i++) { - if ((array[i].getStartPC() < b.getStartPC()) || (array[i].getThisPC() > b.getTarget().getThisPC())) { - sb.append(" "); - } else { - if (b.isConditional()) { - sb.append("?-"); - } else { - sb.append("+-"); - } - i++; - while ((i < array.length) && (array[i].getStartPC() < b.getTarget().getThisPC())) { - sb.append("----"); - i++; - } - sb.append("->"); - sb.append(b.getTarget().getThisPC()); - - } - } - } else { - for (int i = 0; i < array.length; i++) { - if ((array[i].getStartPC() < b.getTarget().getThisPC()) || (array[i].getThisPC() > b.getThisPC())) { - sb.append(" "); - } else { - sb.append("<-"); - i++; - while ((i < array.length) && (array[i].getStartPC() < b.getThisPC())) { - sb.append("----"); - i++; - } - if (b.isConditional()) { - sb.append("-?"); - } else { - sb.append("-+"); - } - } - } - } - } - - return (sb.toString()); - } - - public Instruction getTail() { - return (tail); - } - - public Instruction getHead() { - return (head); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.instruction; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.aparapi.Config; +import com.aparapi.internal.exception.ClassParseException; +import com.aparapi.internal.instruction.InstructionSet.AssignToLocalVariable; +import com.aparapi.internal.instruction.InstructionSet.Branch; +import com.aparapi.internal.instruction.InstructionSet.ByteCode; +import com.aparapi.internal.instruction.InstructionSet.CompositeArbitraryScopeInstruction; +import com.aparapi.internal.instruction.InstructionSet.CompositeInstruction; +import com.aparapi.internal.instruction.InstructionSet.ConditionalBranch; +import com.aparapi.internal.instruction.InstructionSet.FakeGoto; +import com.aparapi.internal.instruction.InstructionSet.Return; +import com.aparapi.internal.instruction.InstructionSet.UnconditionalBranch; +import com.aparapi.internal.model.MethodModel; +import com.aparapi.internal.model.ClassModel.LocalVariableTableEntry; +import com.aparapi.internal.model.ClassModel.LocalVariableInfo; + +/** + * Essentially a glorified linked list of Instructions plus some additional state to allow us to transform sequences. + * + * ExpressionLists do have the notion of a parent which allows us to clone an existing parent, allow transformations + * and then possibly commit or abort the transformations at will. + * @author gfrost + * + */ +public class ExpressionList{ + + private static Logger logger = Logger.getLogger(Config.getLoggerName()); + + private final MethodModel methodModel; + + private final ExpressionList parent; + + private Instruction head; + + private Instruction tail; + + private final Instruction instruction; + + private ExpressionList(MethodModel _methodModel, ExpressionList _parent, Instruction _instruction) { + + methodModel = _methodModel; + parent = _parent; + instruction = _instruction; + if (parent != null) { + head = parent.head; + tail = parent.tail; + } + if (instruction != null) { + tail = _instruction.getPrevExpr(); + tail.setNextExpr(null); + _instruction.setPrevExpr(null); + } + } + + public ExpressionList(MethodModel _methodModel) { + this(_methodModel, null, null); + } + + /** + * Determine whether the sequence of instructions from _start to _extent is free of branches which extend beyond _extent. + * + * As a side effect, if we find a possible branch it is likely a break or continue so we mark the conditional as such. + * + * @param _start + * @param _extent + * @return + */ + public boolean doesNotContainContinueOrBreak(Instruction _start, Instruction _extent) { + boolean ok = true; + boolean breakOrContinue = false; + for (Instruction i = _start; i != null; i = i.getNextExpr()) { + if (i.isBranch()) { + if (i.asBranch().isForwardUnconditional() && i.asBranch().getTarget().isAfter(_extent)) { + breakOrContinue = true; + } else { + ok = false; + break; + } + } + } + if (ok) { + if (breakOrContinue) { + for (Instruction i = _start; i != null; i = i.getNextExpr()) { + if (i.isBranch() && i.asBranch().isForwardUnconditional() && i.asBranch().getTarget().isAfter(_extent)) { + i.asBranch().setBreakOrContinue(true); + } + } + } + } + return (ok); + } + + public boolean doesNotContainCompositeOrBranch(Instruction _start, Instruction _exclusiveEnd) { + boolean ok = true; + for (Instruction i = _start; (i != null) && (i != _exclusiveEnd); i = i.getNextExpr()) { + if (!(i instanceof CompositeInstruction) && (i.isBranch())) { + ok = false; + break; + } + } + return (ok); + } + + public void unwind() { + if (parent != null) { + if (instruction != null) { + tail.setNextExpr(instruction); + instruction.setPrevExpr(tail); + parent.head = head; + } else { + parent.head = head; + parent.tail = tail; + } + } + } + + /** + * [1] [2] [3] [4] + * + * Note that passing null here essentially deletes the existing expression list and returns the expression + * + * @param _newTail + * @return + */ + + public Instruction createList(final Instruction _newTail) { + Instruction childExprHead = null; + if (_newTail == null) { + childExprHead = head; + tail = head = null; + } else { + childExprHead = _newTail.getNextExpr(); + tail = _newTail; + _newTail.setNextExpr(null); + if (childExprHead != null) { + childExprHead.setPrevExpr(null); + } + + } + return (childExprHead); + } + + /** + * Add this instruction to the end of the list. + * + * @param _instruction + * @return The instruction we added + */ + + public Instruction add(Instruction _instruction) { + + if (head == null) { + head = _instruction; + } else { + _instruction.setPrevExpr(tail); + tail.setNextExpr(_instruction); + + } + + tail = _instruction; + logger.log(Level.FINE, "After PUSH of " + _instruction + " tail=" + tail); + return (tail); + } + + /** + * Insert the given instruction (_newone) between the existing entries (_prev and _next). + * @param _prev + * @param _next + * @param _newOne + */ + public void insertBetween(Instruction _prev, Instruction _next, Instruction _newOne) { + _newOne.setNextExpr(null); + _newOne.setPrevExpr(null); + if (_prev == null) { + // this is the new head + if (_next == null) { + head = tail = _newOne; + } else { + _newOne.setNextExpr(head); + head.setPrevExpr(_newOne); + head = _newOne; + } + } else if (_next == null) { + _newOne.setPrevExpr(tail); + tail.setNextExpr(_newOne); + tail = _newOne; + } else { + _newOne.setNextExpr(_prev.getNextExpr()); + _newOne.setPrevExpr(_next.getPrevExpr()); + _prev.setNextExpr(_newOne); + _next.setPrevExpr(_newOne); + } + + } + + /** + * Inclusive replace between _head and _tail with _newOne. + * + * <pre> + * | | --> | | ---> ... ---> | | ---> | | + * | prev | | _head | | _tail | | next | + * | | <-- | | <--- ... <----| | <--- | | + * </pre> + * To + * <pre> + * | | --> | | ---> | | + * | prev | | _newOne | | next | + * | | <-- | | <--- | | + * </pre> + */ + + public void replaceInclusive(Instruction _head, Instruction _tail, Instruction _newOne) { + _newOne.setNextExpr(null); + _newOne.setPrevExpr(null); + final Instruction prevHead = _head.getPrevExpr(); + if (_tail == null) { + // this is the new tail + _newOne.setPrevExpr(prevHead); + prevHead.setNextExpr(_newOne); + tail = _newOne; + } else { + final Instruction tailNext = _tail.getNextExpr(); + if (prevHead == null) { + // this is the new head + if (tailNext == null) { + head = tail = _newOne; + } else { + _newOne.setNextExpr(head); + head.setPrevExpr(_newOne); + head = _newOne; + } + } else if (tailNext == null) { + _newOne.setPrevExpr(prevHead); + prevHead.setNextExpr(_newOne); + tail = _newOne; + _head.setPrevExpr(null); + } else { + _newOne.setNextExpr(tailNext); + _newOne.setPrevExpr(prevHead); + prevHead.setNextExpr(_newOne); + tailNext.setPrevExpr(_newOne); + + } + _tail.setNextExpr(null); + _head.setPrevExpr(null); + } + + } + + /** + * Fold headTail.tail into valid composites + * + * <pre> + * if(??){then}... + * ?? ?> [THEN] ... + * --------> + * + * if (??){THEN}else{ELSE}... + * + * ?? ?> [THEN] >> [ELSE] ... + * ------------> + * --------> + * + * sun for (INIT,??,DELTA){BODY} ... + * + * [INIT] ?? ?> [BODY] [DELTA] << ... + * ------------------> + * <------------------- + * + * sun for (,??,DELTA){BODY} ... + * + * ?? ?> [BODY] [DELTA] << ... + * ------------------> + * <------------------- + * + * sun while (?){l} ... + * + * ?? ?> [BODY] << ... + * -----------> + * <------------ + * + * eclipse for (INIT,??,DELTA){BODY} ... + * [INIT] >> [BODY] [DELTA] ?? ?< ... + * ----------------> + * <----------------- + * + * eclipse for (,??,DELTA){BODY} ... + * >> [BODY] [DELTA] ?? ?< ... + * ---------------> + * <----------------- + * + * eclipse while (??){BODY} ... + * >> [BODY] ?? ?< ... + * --------> + * <---------- + * + * eclipe if (?1) { while (?2) {BODY} } else {ELSE} ... + * ?1 ?> >> [BODY] ?2 ?< >> [ELSE] ... + * ---------> + * <--------- + * ---------------------> + * --------> + * + * sun for (,?1,DELTA){ if (?2) { THEN break; } BODY} ... + * + * ?1 ?> ?2 ?> [THEN] >> [BODY] [DELTA] << ... + * -----------> + * ----------------------------------> + * ------------------> + * <------------------------------------ + * + * sun for (,?1,DELTA){ if (?2) { THEN continue; } BODY} ... + * + * ?1 ?> ?2 ?> THEN >> [BODY] [DELTA] << ... + * ---------> + * --------> + * --------------------------------> + * <---------------------------------- + * + * Some exceptions based on sun javac optimizations + * + * if (?1){ if (?2){THEN} }else{ ELSE } ... + * One might expect + * ?1 ?> ?2 ?> [THEN] >> [ELSE] ... + * -----------------> + * -------->! + * -------------> + * However the conditional branch to the unconditional (!) is optimized away and instead the unconditional inverted and extended + * + * ?1 ?> ?2 ?> [THEN] >> [ELSE] ... + * -----------------> + * --------*---------> + * + * sun if (?1) { while (?2) {l} } else {e} ... + * One might expect + * ?1 ?> ?2 ?> [BODY] << >> [ELSE] ... + * -------------------> + * ----------->! + * <---------- + * --------> + * + * However as above the conditional branch to the unconditional (!) can be optimized away and the conditional inverted and extended + * ?1 ?> ?2 ?> [BODY] << >> [ELSE] ... + * --------------------> + * -----------*---------> + * <----------- + * + * However we can also now remove the forward unconditional completely as it is unreachable + * ?1 ?> ?2 ?> [BODY] << [ELSE] ... + * -----------------> + * ------------------> + * <----------- + * + * sun while(?1){if (?2) {THEN} else {ELSE} } ... + * One might expect + * ?1 ?> ?2 ?> [BODY] >> [ELSE] << ... + * --------------------------> + * <--------------------- + * ----------> + * ------->! + * + * However the unconditional branch to the unconditional backbranch (!) can be optimized away and the unconditional wrapped back directly to the loop control head + * ?1 ?> ?2 ?> [BODY] << [ELSE] << ... + * --------------------------> + * <--------------------- + * ----------> + * <----------- + + * </pre> + * @param _instruction + * @throws ClassParseException + */ + public boolean foldComposite(final Instruction _instruction) throws ClassParseException { + boolean handled = false; + try { + + if (logger.isLoggable(Level.FINE)) { + System.out.println("foldComposite: curr = " + _instruction); + System.out.println(dumpDiagram(_instruction)); + // System.out.println(dumpDiagram(null, _instruction)); + } + if (_instruction.isForwardBranchTarget() || ((tail != null) && tail.isBranch() && tail.asBranch().isReverseConditional())) { + while (_instruction.isForwardBranchTarget() + || ((tail != null) && tail.isBranch() && tail.asBranch().isReverseConditional())) { + if (logger.isLoggable(Level.FINE)) { + System.out.println(dumpDiagram(_instruction)); + + } + handled = false; + + if ((tail != null) && tail.isBranch() && tail.asBranch().isReverseConditional()) { + /** + * This looks like an eclipse style for/while loop or possibly a do{}while() + * <pre> + * eclipse for (INIT,??,DELTA){BODY} ... + * [INIT] >> [BODY] [DELTA] ?? ?< ... + * ----------------> + * <----------------- + * + * eclipse for (,??,DELTA){BODY} ... + * >> [BODY] [DELTA] ?? ?< ... + * ---------------> + * <----------------- + * + * do {BODY} while(??) + * [BODY] ?? ?< ... + * <----------- + * + * eclipse while (??){BODY} ... + * >> [BODY] ?? ?< ... + * --------> + * <---------- + * </pre> + **/ + final BranchSet branchSet = ((ConditionalBranch) tail.asBranch()).getOrCreateBranchSet(); + Instruction loopTop = branchSet.getTarget().getRootExpr(); + final Instruction beginingOfBranch = branchSet.getFirst(); + + final Instruction startOfBeginningOfBranch = beginingOfBranch.getStartInstruction(); + // empty loops sometimes look like eclipse loops! + if (startOfBeginningOfBranch == loopTop) { + + loopTop = loopTop.getPrevExpr(); + if (loopTop instanceof AssignToLocalVariable) { + final LocalVariableInfo localVariableInfo = ((AssignToLocalVariable) loopTop).getLocalVariableInfo(); + if ((localVariableInfo.getStart() == loopTop.getNextExpr().getStartPC()) + && (localVariableInfo.getEnd() == _instruction.getThisPC())) { + loopTop = loopTop.getPrevExpr(); // back up over the initialization + } + } + addAsComposites(ByteCode.COMPOSITE_EMPTY_LOOP, loopTop, branchSet); + handled = true; + } else { + + if ((loopTop.getPrevExpr() != null) && loopTop.getPrevExpr().isBranch() + && loopTop.getPrevExpr().asBranch().isForwardUnconditional()) { + if (doesNotContainCompositeOrBranch(branchSet.getTarget().getRootExpr(), branchSet.getFirst().getPrevExpr())) { + branchSet.unhook(); + loopTop.getPrevExpr().asBranch().unhook(); + loopTop = loopTop.getPrevExpr(); + // looptop == the unconditional? + loopTop = loopTop.getPrevExpr(); + if (loopTop instanceof AssignToLocalVariable) { + final LocalVariableInfo localVariableInfo = ((AssignToLocalVariable) loopTop).getLocalVariableInfo(); + if ((localVariableInfo.getStart() == loopTop.getNextExpr().getStartPC()) + && (localVariableInfo.getEnd() == _instruction.getThisPC())) { + loopTop = loopTop.getPrevExpr(); // back up over the initialization + } + } + addAsComposites(ByteCode.COMPOSITE_FOR_ECLIPSE, loopTop, branchSet); + handled = true; + } + } + if (!handled) { + // do{}while()_ do not require any previous instruction + if (loopTop.getPrevExpr() == null) { + throw new IllegalStateException("might be a dowhile with no provious expression"); + + } else if (!(loopTop.getPrevExpr().isBranch() && loopTop.getPrevExpr().asBranch().isForwardUnconditional())) { + if (doesNotContainCompositeOrBranch(branchSet.getTarget().getRootExpr(), branchSet.getFirst() + .getPrevExpr())) { + loopTop = loopTop.getPrevExpr(); + branchSet.unhook(); + addAsComposites(ByteCode.COMPOSITE_DO_WHILE, loopTop, branchSet); + handled = true; + } + } else { + throw new IllegalStateException("might be mistaken for a do while!"); + } + } + } + } + if (!handled && _instruction.isForwardConditionalBranchTarget() && tail.isBranch() + && tail.asBranch().isReverseUnconditional()) { + + /** + * This is s sun style loop + * <pre> + * sun for (INIT,??,DELTA){BODY} ... + * + * [INIT] ?? ?> [BODY] [DELTA] << ... + * ------------------> + * <------------------- + * + * sun for (,??,DELTA){BODY} ... + * + * ?? ?> [BODY] [DELTA] << ... + * ------------------> + * <------------------- + * + * sun while (?){l} ... + * + * ?? ?> [BODY] << ... + * -----------> + * <------------ + * + *</pre> + */ + final ConditionalBranch lastForwardConditional = _instruction.getForwardConditionalBranches().getLast(); + final BranchSet branchSet = lastForwardConditional.getOrCreateBranchSet(); + final Branch reverseGoto = tail.asBranch(); + final Instruction loopBackTarget = reverseGoto.getTarget(); + if (loopBackTarget.getReverseUnconditionalBranches().size() > 1) { + throw new ClassParseException(ClassParseException.TYPE.CONFUSINGBRANCHESPOSSIBLYCONTINUE); + } + if (_instruction.isForwardUnconditionalBranchTarget()) { + /** + * Check if we have a break + * <pre> + * ?? ?> [BODY] ?1 ?> >> [BODY] << ... + * --------------------------> + * ----> + * -----------> + * <---------------------------- + * + *</pre> + */ + final Branch lastForwardUnconditional = _instruction.getForwardUnconditionalBranches().getLast(); + if ((lastForwardUnconditional != null) && lastForwardUnconditional.isAfter(lastForwardConditional)) { + throw new ClassParseException(ClassParseException.TYPE.CONFUSINGBRANCHESPOSSIBLYBREAK); + } + } + if (loopBackTarget != branchSet.getFirst().getStartInstruction()) { + /** + * we may have a if(?1){while(?2){}}else{...} where the else goto has been optimized away. + * <pre> + * One might expect + * ?1 ?> ?2 ?> [BODY] << >> [ELSE] ... + * -------------------> + * ----------->! + * <---------- + * --------> + * + * However as above the conditional branch to the unconditional (!) can be optimized away and the conditional inverted and extended + * ?1 ?> ?2 ?> [BODY] << >> [ELSE] ... + * --------------------> + * -----------*---------> + * <----------- + * + * However we can also now remove the forward unconditional completely as it is unreachable + * ?1 ?> ?2 ?> [BODY] << [ELSE] ... + * -----------------> + * ------------------> + * <----------- + * + * </pre> + */ + + final Instruction loopbackTargetRoot = loopBackTarget.getRootExpr(); + if (loopbackTargetRoot.isBranch() && loopbackTargetRoot.asBranch().isConditional()) { + final ConditionalBranch topOfRealLoop = (ConditionalBranch) loopbackTargetRoot.asBranch(); + BranchSet extentBranchSet = topOfRealLoop.getBranchSet(); + if (topOfRealLoop.getBranchSet() == null) { + extentBranchSet = topOfRealLoop.findEndOfConditionalBranchSet(_instruction.getNextPC()) + .getOrCreateBranchSet(); + } + // We believe that this extendBranchSet is the real top of the while. + if (doesNotContainCompositeOrBranch(extentBranchSet.getLast().getNextExpr(), reverseGoto)) { + + Instruction loopTop = topOfRealLoop.getPrevExpr(); + if (loopTop instanceof AssignToLocalVariable) { + final LocalVariableInfo localVariableInfo = ((AssignToLocalVariable) loopTop).getLocalVariableInfo(); + if ((localVariableInfo.getStart() == loopTop.getNextExpr().getStartPC()) + && (localVariableInfo.getEnd() == _instruction.getThisPC())) { + loopTop = loopTop.getPrevExpr(); // back up over the initialization + } + } + extentBranchSet.unhook(); + + addAsComposites(ByteCode.COMPOSITE_FOR_SUN, loopTop, extentBranchSet); + final UnconditionalBranch fakeGoto = new FakeGoto(methodModel, extentBranchSet.getLast().getTarget()); + + add(fakeGoto); + extentBranchSet.getLast().getTarget().addBranchTarget(fakeGoto); + + handled = true; + } + } + } else { + /** + * Just a normal sun style loop + */ + if (doesNotContainCompositeOrBranch(branchSet.getLast().getNextExpr(), reverseGoto)) { + Instruction loopTop = reverseGoto.getTarget().getRootExpr().getPrevExpr(); + + if (logger.isLoggable(Level.FINEST)) { + Instruction next = branchSet.getFirst().getNextExpr(); + System.out.println("### for/while candidate exprs: " + branchSet.getFirst()); + while (next != null) { + System.out.println("### expr = " + next); + next = next.getNextExpr(); + } + } + + if (loopTop instanceof AssignToLocalVariable) { + final LocalVariableInfo localVariableInfo = ((AssignToLocalVariable) loopTop).getLocalVariableInfo(); + if ((localVariableInfo.getStart() == loopTop.getNextExpr().getStartPC()) + && (localVariableInfo.getEnd() == _instruction.getThisPC())) { + loopTop = loopTop.getPrevExpr(); // back up over the initialization + + } + } + branchSet.unhook(); + + // If there is an inner scope, it is likely that the loop counter var + // is modified using an inner scope variable so use while rather than for + if (reverseGoto.getPrevExpr() instanceof CompositeArbitraryScopeInstruction) { + addAsComposites(ByteCode.COMPOSITE_WHILE, loopTop, branchSet); + } else { + addAsComposites(ByteCode.COMPOSITE_FOR_SUN, loopTop, branchSet); + } + handled = true; + } + + } + } + if (!handled && !tail.isForwardBranch() && _instruction.isForwardConditionalBranchTarget()) { + /** + * This an if(exp) + *<pre> * + * if(??){then}... + * ?? ?> [THEN] ... + * --------> + * + *</pre> + */ + final ConditionalBranch lastForwardConditional = _instruction.getForwardConditionalBranches().getLast(); + final BranchSet branchSet = lastForwardConditional.getOrCreateBranchSet(); + if (doesNotContainContinueOrBreak(branchSet.getLast().getNextExpr(), _instruction)) { + branchSet.unhook(); + addAsComposites(ByteCode.COMPOSITE_IF, branchSet.getFirst().getPrevExpr(), branchSet); + handled = true; + } + } + if (!handled && !tail.isForwardBranch() && _instruction.isForwardUnconditionalBranchTarget()) { + + final LinkedList<Branch> forwardUnconditionalBranches = _instruction.getForwardUnconditionalBranches(); + + final Branch lastForwardUnconditional = forwardUnconditionalBranches.getLast(); + final Instruction afterGoto = lastForwardUnconditional.getNextExpr(); + if (afterGoto.getStartInstruction().isForwardConditionalBranchTarget()) { + final LinkedList<ConditionalBranch> forwardConditionalBranches = afterGoto.getStartInstruction() + .getForwardConditionalBranches(); + final ConditionalBranch lastForwardConditional = forwardConditionalBranches.getLast(); + final BranchSet branchSet = lastForwardConditional.getOrCreateBranchSet(); + + if (doesNotContainCompositeOrBranch(branchSet.getLast().getNextExpr(), lastForwardUnconditional)) { + if (doesNotContainContinueOrBreak(afterGoto.getNextExpr(), _instruction)) { + branchSet.unhook(); + lastForwardUnconditional.unhook(); + addAsComposites(ByteCode.COMPOSITE_IF_ELSE, branchSet.getFirst().getPrevExpr(), branchSet); + handled = true; + } + } else { + //then not clean. + final ExpressionList newHeadTail = new ExpressionList(methodModel, this, lastForwardUnconditional); + handled = newHeadTail.foldComposite(lastForwardUnconditional.getStartInstruction()); + newHeadTail.unwind(); + // handled = foldCompositeRecurse(lastForwardUnconditional); + if (!handled && (forwardUnconditionalBranches.size() > 1)) { + // BI AI AE BE + // ?> ?> .. >> .. >> C S + // ?---------------------->22 + // ?---------->18 + // +-------------->31 + // +------>31 + // Javac sometimes performs the above optimization. Basically the GOTO for the inner IFELSE(AI,AE) instead of targeting the GOTO + // from the outer IFELSE(B1,BE) so instead of AE->BE->... we have AE-->... + // + // So given more than one target we retreat up the list of unconditionals until we find a clean one treating the previously visited GOTO + // as a possible end + + for (int i = forwardUnconditionalBranches.size(); i > 1; i--) { + final Branch thisGoto = forwardUnconditionalBranches.get(i - 1); + final Branch elseGoto = forwardUnconditionalBranches.get(i - 2); + final Instruction afterElseGoto = elseGoto.getNextExpr(); + if (afterElseGoto.getStartInstruction().isConditionalBranchTarget()) { + final BranchSet elseBranchSet = afterElseGoto.getStartInstruction() + .getForwardConditionalBranches().getLast().getOrCreateBranchSet(); + if (doesNotContainCompositeOrBranch(elseBranchSet.getLast().getNextExpr(), elseGoto)) { + if (doesNotContainCompositeOrBranch(afterElseGoto.getNextExpr(), thisGoto)) { + if (logger.isLoggable(Level.FINE)) { + System.out.println(dumpDiagram(_instruction)); + } + elseBranchSet.unhook(); + elseGoto.unhook(); + if (logger.isLoggable(Level.FINE)) { + System.out.println(dumpDiagram(_instruction)); + + } + + final CompositeInstruction composite = CompositeInstruction.create( + ByteCode.COMPOSITE_IF_ELSE, methodModel, elseBranchSet.getFirst(), thisGoto, + elseBranchSet); + replaceInclusive(elseBranchSet.getFirst(), thisGoto.getPrevExpr(), composite); + + handled = true; + + break; + } + } + } + + } + + } + } + + } + + } + if (!handled && !tail.isForwardBranch() && _instruction.isForwardConditionalBranchTarget() + && _instruction.isForwardUnconditionalBranchTarget()) { + // here we have multiple composites ending at the same point + + final Branch lastForwardUnconditional = _instruction.getForwardUnconditionalBranches().getLast(); + final ConditionalBranch lastForwardConditional = _instruction.getStartInstruction() + .getForwardConditionalBranches().getLast(); + // we will clip the tail and see if recursing helps + + if (lastForwardConditional.getTarget().isAfter(lastForwardUnconditional)) { + + lastForwardConditional.retarget(lastForwardUnconditional); + + final ExpressionList newHeadTail = new ExpressionList(methodModel, this, lastForwardUnconditional); + handled = newHeadTail.foldComposite(lastForwardUnconditional.getStartInstruction()); + newHeadTail.unwind(); + + } + + } + if (!handled) { + break; + } + } + + } else { + + // might be end of arbitrary scope + final LocalVariableTableEntry<LocalVariableInfo> localVariableTable = methodModel.getMethod() + .getLocalVariableTableEntry(); + int startPc = Short.MAX_VALUE; + + for (final LocalVariableInfo localVariableInfo : localVariableTable) { + if (localVariableInfo.getEnd() == _instruction.getThisPC()) { + logger.fine(localVariableInfo.getVariableName() + " scope " + localVariableInfo.getStart() + " ," + + localVariableInfo.getEnd()); + if (localVariableInfo.getStart() < startPc) { + startPc = localVariableInfo.getStart(); + } + } + } + if (startPc < Short.MAX_VALUE) { + logger.fine("Scope block from " + startPc + " to " + (tail.getThisPC() + tail.getLength())); + for (Instruction i = head; i != null; i = i.getNextPC()) { + if (i.getThisPC() == startPc) { + final Instruction startInstruction = i.getRootExpr().getPrevExpr(); + logger.fine("Start = " + startInstruction); + + addAsComposites(ByteCode.COMPOSITE_ARBITRARY_SCOPE, startInstruction.getPrevExpr(), null); + handled = true; + break; + } + } + + } + + } + + if (Config.instructionListener != null) { + Config.instructionListener.showAndTell("after folding", head, _instruction); + } + + } catch (final ClassParseException _classParseException) { + throw new ClassParseException(_classParseException); + } catch (final Throwable t) { + throw new ClassParseException(t); + + } + return (handled); + } + + private void addAsComposites(ByteCode _byteCode, Instruction _start, BranchSet _branchSet) { + final Instruction childTail = tail; + final Instruction childHead = createList(_start); + final CompositeInstruction composite = CompositeInstruction.create(_byteCode, methodModel, childHead, childTail, _branchSet); + add(composite); + } + + /** + * Aids debugging. Creates a diagrammatic form of the roots (+ tail instruction) so that we can analyze control flow. + * <pre> + * I I I C C I U I U[I]I + * |---------->1 + * |---->1 + * |------>2 + * |-->2 + * </pre> + * @param _cursor The instruction we are looking at + * @param _instruction The instruction we are considering adding (may be null) + * @return + */ + public String dumpDiagram(Instruction _instruction) { + final StringBuilder sb = new StringBuilder(); + final List<Instruction> list = new ArrayList<Instruction>(); + + for (Instruction i = head; i != null; i = i.getNextExpr()) { + list.add(i); + } + + for (Instruction i = _instruction; i != null; i = i.getNextPC()) { + list.add(i); + } + + final Instruction[] array = list.toArray(new Instruction[0]); + boolean lastWasCursor = false; + + final List<Branch> branches = new ArrayList<Branch>(); + for (final Instruction i : list) { + sb.append(String.format(" %3d", i.getStartPC())); + } + + sb.append("\n"); + for (final Instruction i : list) { + sb.append(String.format(" %3d", i.getThisPC())); + } + + sb.append("\n"); + for (final Instruction i : list) { + + if (i == _instruction) { + sb.append(" ["); + lastWasCursor = true; + } else { + if (lastWasCursor) { + sb.append("] "); + lastWasCursor = false; + } else { + sb.append(" "); + } + } + if (i.isBranch() && i.asBranch().isConditional()) { + branches.add(i.asBranch()); + + if (i.asBranch().isForward()) { + sb.append("?>"); + + } else { + sb.append("?<"); + } + } else if (i.isBranch() && i.asBranch().isUnconditional()) { + branches.add(i.asBranch()); + if (i.asBranch().isForward()) { + sb.append(">>"); + } else { + sb.append("<<"); + } + } else if (i instanceof CompositeInstruction) { + sb.append(" C"); + } else if (i instanceof Return) { + + sb.append(" R"); + // } else if (i instanceof AssignToLocalVariable) { + // sb.append(" S"); + } else { + sb.append(".."); + } + } + + if (lastWasCursor) { + sb.append("] "); + } else { + sb.append(" "); + } + + for (final Branch b : branches) { + sb.append("\n "); + if (b.isForward()) { + for (int i = 0; i < array.length; i++) { + if ((array[i].getStartPC() < b.getStartPC()) || (array[i].getThisPC() > b.getTarget().getThisPC())) { + sb.append(" "); + } else { + if (b.isConditional()) { + sb.append("?-"); + } else { + sb.append("+-"); + } + i++; + while ((i < array.length) && (array[i].getStartPC() < b.getTarget().getThisPC())) { + sb.append("----"); + i++; + } + sb.append("->"); + sb.append(b.getTarget().getThisPC()); + + } + } + } else { + for (int i = 0; i < array.length; i++) { + if ((array[i].getStartPC() < b.getTarget().getThisPC()) || (array[i].getThisPC() > b.getThisPC())) { + sb.append(" "); + } else { + sb.append("<-"); + i++; + while ((i < array.length) && (array[i].getStartPC() < b.getThisPC())) { + sb.append("----"); + i++; + } + if (b.isConditional()) { + sb.append("-?"); + } else { + sb.append("-+"); + } + } + } + } + } + + return (sb.toString()); + } + + public Instruction getTail() { + return (tail); + } + + public Instruction getHead() { + return (head); + } +} diff --git a/src/main/java/com/aparapi/internal/instruction/Instruction.java b/src/main/java/com/aparapi/internal/instruction/Instruction.java index 9d3b2352580aaf23a2590a6cfda3b4c7eb66d865..055f2424129479829a93a63393b831bfa71642ec 100644 --- a/src/main/java/com/aparapi/internal/instruction/Instruction.java +++ b/src/main/java/com/aparapi/internal/instruction/Instruction.java @@ -1,402 +1,402 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.instruction; - -import java.util.LinkedList; - -import com.aparapi.internal.instruction.InstructionSet.Branch; -import com.aparapi.internal.instruction.InstructionSet.ByteCode; -import com.aparapi.internal.instruction.InstructionSet.CompositeInstruction; -import com.aparapi.internal.instruction.InstructionSet.ConditionalBranch; -import com.aparapi.internal.model.MethodModel; -import com.aparapi.internal.reader.ByteReader; - -/** - * Initially represents a single Java bytecode instruction. - * - * Instructions for each bytecode are created when the bytecode is first scanned. - * - * Each Instruction will contain a pc (program counter) offset from the beginning of the sequence of bytecode and the length will be determined by the information gleaned from InstructionSet.BYTECODE. - * - * - * @author gfrost - * - */ -public abstract class Instruction{ - - protected MethodModel method; - - private final ByteCode byteCode; - - private int length; - - protected int pc; - - abstract String getDescription(); - - private Instruction nextPC = null; - - private Instruction prevPC = null; - - private Instruction nextExpr = null; - - private Instruction prevExpr = null; - - private Instruction parentExpr = null; - - private LinkedList<ConditionalBranch> forwardConditionalBranchTargets; - - private LinkedList<ConditionalBranch> reverseConditionalBranchTargets; - - private LinkedList<Branch> forwardUnconditionalBranchTargets; - - private LinkedList<Branch> reverseUnconditionalBranchTargets; - - private Instruction firstChild = null; - - private Instruction lastChild = null; - - public void setChildren(Instruction _firstChild, Instruction _lastChild) { - - if ((_firstChild == null) || (_lastChild == null)) { - throw new IllegalStateException("null children added"); - } - firstChild = _firstChild; - lastChild = _lastChild; - - for (Instruction i = firstChild; i != lastChild; i = i.getNextExpr()) { - if (i == null) { - throw new IllegalStateException("child list broken "); - } - i.setParentExpr(this); - } - lastChild.setParentExpr(this); - } - - public Instruction getPrevExpr() { - return (prevExpr); - - } - - public Instruction getNextExpr() { - return (nextExpr); - } - - public void setNextPC(Instruction _nextByPC) { - nextPC = _nextByPC; - } - - public void setPrevPC(Instruction _prevByPC) { - prevPC = _prevByPC; - } - - public void setPrevExpr(Instruction _prevExpr) { - prevExpr = _prevExpr; - } - - public void setNextExpr(Instruction _nextExpr) { - nextExpr = _nextExpr; - } - - public Instruction toInstruction() { - return (this); - } - - public int getLength() { - return (length); - } - - public void setLength(int _length) { - length = _length; - } - - public final ByteCode getByteCode() { - return (byteCode); - } - - public int getThisPC() { - return (pc); - } - - public int getStartPC() { - return (getFirstChild() == null ? pc : getFirstChild().getStartPC()); - } - - protected Instruction(MethodModel _method, ByteCode _byteCode, int _pc) { - method = _method; - pc = _pc; - byteCode = _byteCode; - } - - protected Instruction(MethodModel _method, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - this(_method, _byteCode, _wide ? _byteReader.getOffset() - 2 : _byteReader.getOffset() - 1); - } - - // This works for most cases (except calls whose operand count depends upon the signature) so all call instructions therefore override this method - public int getStackConsumeCount() { - return (byteCode.getPop().getStackAdjust()); - } - - public int getStackProduceCount() { - return (byteCode.getPush().getStackAdjust()); - } - - public int getStackDelta() { - return (getStackProduceCount() - getStackConsumeCount()); - } - - @Override public String toString() { - return pc + " " + byteCode.getName(); - } - - public boolean isBranch() { - return (this instanceof Branch); - } - - public int compareTo(Instruction _other) { - return (pc - _other.pc); - } - - public boolean isAfter(Instruction _other) { - return (compareTo(_other) > 0); - } - - public boolean isAfterOrEqual(Instruction _other) { - return (compareTo(_other) >= 0); - } - - public boolean isBefore(Instruction _other) { - return (compareTo(_other) < 0); - } - - public boolean isBeforeOrEqual(Instruction _other) { - return (compareTo(_other) <= 0); - } - - public Instruction getFirstChild() { - return (firstChild); - } - - public Instruction getLastChild() { - return (lastChild); - } - - public Instruction getStartInstruction() { - return (getFirstChild() == null ? this : getFirstChild().getStartInstruction()); - } - - public MethodModel getMethod() { - return (method); - } - - public Instruction getNextPC() { - return (nextPC); - } - - public Instruction getPrevPC() { - return (prevPC); - } - - public void setParentExpr(Instruction _parentExpr) { - parentExpr = _parentExpr; - } - - public Instruction getParentExpr() { - return (parentExpr); - } - - public Instruction getRootExpr() { - return (parentExpr == null ? this : parentExpr.getRootExpr()); - } - - public boolean isReverseConditionalBranchTarget() { - return ((reverseConditionalBranchTargets != null) && (reverseConditionalBranchTargets.size() > 0)); - } - - public boolean isForwardConditionalBranchTarget() { - return ((forwardConditionalBranchTargets != null) && (forwardConditionalBranchTargets.size() > 0)); - } - - public boolean isReverseUnconditionalBranchTarget() { - return ((reverseUnconditionalBranchTargets != null) && (reverseUnconditionalBranchTargets.size() > 0)); - } - - public boolean isForwardUnconditionalBranchTarget() { - return ((forwardUnconditionalBranchTargets != null) && (forwardUnconditionalBranchTargets.size() > 0)); - } - - public boolean isReverseBranchTarget() { - return (isReverseConditionalBranchTarget() || isReverseUnconditionalBranchTarget()); - } - - public boolean isConditionalBranchTarget() { - return (isReverseConditionalBranchTarget() || isForwardConditionalBranchTarget()); - } - - public boolean isUnconditionalBranchTarget() { - return (isReverseUnconditionalBranchTarget() || isForwardUnconditionalBranchTarget()); - } - - public boolean isForwardBranchTarget() { - return (isForwardConditionalBranchTarget() || isForwardUnconditionalBranchTarget()); - } - - public boolean isBranchTarget() { - return (isForwardBranchTarget() || isReverseBranchTarget()); - } - - public boolean producesStack() { - return ((this instanceof CompositeInstruction) || (getStackProduceCount() > 0)); - } - - public Instruction getReal() { - return (this); - } - - public Branch asBranch() { - return ((Branch) this); - } - - public boolean consumesStack() { - return (getStackConsumeCount() > 0); - } - - public void addBranchTarget(Branch _branch) { - - if (_branch.isReverse()) { - if (_branch.isConditional()) { - if (reverseConditionalBranchTargets == null) { - reverseConditionalBranchTargets = new LinkedList<ConditionalBranch>(); - } - reverseConditionalBranchTargets.add((ConditionalBranch) _branch); - } else { - if (reverseUnconditionalBranchTargets == null) { - reverseUnconditionalBranchTargets = new LinkedList<Branch>(); - } - reverseUnconditionalBranchTargets.add(_branch); - } - } else { - if (_branch.isConditional()) { - if (forwardConditionalBranchTargets == null) { - forwardConditionalBranchTargets = new LinkedList<ConditionalBranch>(); - } - forwardConditionalBranchTargets.add((ConditionalBranch) _branch); - } else { - if (forwardUnconditionalBranchTargets == null) { - forwardUnconditionalBranchTargets = new LinkedList<Branch>(); - } - forwardUnconditionalBranchTargets.add(_branch); - } - } - } - - public void removeBranchTarget(Branch _branch) { - if (_branch.isReverse()) { - if (_branch.isConditional()) { - if (reverseConditionalBranchTargets != null) { - reverseConditionalBranchTargets.remove(_branch); - if (reverseConditionalBranchTargets.size() == 0) { - reverseConditionalBranchTargets = null; - } - } - } else { - if (reverseUnconditionalBranchTargets != null) { - reverseUnconditionalBranchTargets.remove(_branch); - if (reverseUnconditionalBranchTargets.size() == 0) { - reverseUnconditionalBranchTargets = null; - } - } - } - } else { - if (_branch.isConditional()) { - if (forwardConditionalBranchTargets != null) { - forwardConditionalBranchTargets.remove(_branch); - if (forwardConditionalBranchTargets.size() == 0) { - forwardConditionalBranchTargets = null; - } - } - } else { - if (forwardUnconditionalBranchTargets != null) { - forwardUnconditionalBranchTargets.remove(_branch); - if (forwardUnconditionalBranchTargets.size() == 0) { - forwardUnconditionalBranchTargets = null; - } - } - } - } - } - - public LinkedList<Branch> getForwardUnconditionalBranches() { - return (forwardUnconditionalBranchTargets); - } - - public LinkedList<ConditionalBranch> getForwardConditionalBranches() { - return (forwardConditionalBranchTargets); - } - - public LinkedList<Branch> getReverseUnconditionalBranches() { - return (reverseUnconditionalBranchTargets); - } - - public LinkedList<ConditionalBranch> getReverseConditionalBranches() { - return (reverseConditionalBranchTargets); - } - - public boolean isForwardBranch() { - return (isBranch() && asBranch().isForward()); - } - - public boolean sameAs(Instruction _other) { - return (equals(_other)); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.instruction; + +import java.util.LinkedList; + +import com.aparapi.internal.instruction.InstructionSet.Branch; +import com.aparapi.internal.instruction.InstructionSet.ByteCode; +import com.aparapi.internal.instruction.InstructionSet.CompositeInstruction; +import com.aparapi.internal.instruction.InstructionSet.ConditionalBranch; +import com.aparapi.internal.model.MethodModel; +import com.aparapi.internal.reader.ByteReader; + +/** + * Initially represents a single Java bytecode instruction. + * + * Instructions for each bytecode are created when the bytecode is first scanned. + * + * Each Instruction will contain a pc (program counter) offset from the beginning of the sequence of bytecode and the length will be determined by the information gleaned from InstructionSet.BYTECODE. + * + * + * @author gfrost + * + */ +public abstract class Instruction{ + + protected MethodModel method; + + private final ByteCode byteCode; + + private int length; + + protected int pc; + + abstract String getDescription(); + + private Instruction nextPC = null; + + private Instruction prevPC = null; + + private Instruction nextExpr = null; + + private Instruction prevExpr = null; + + private Instruction parentExpr = null; + + private LinkedList<ConditionalBranch> forwardConditionalBranchTargets; + + private LinkedList<ConditionalBranch> reverseConditionalBranchTargets; + + private LinkedList<Branch> forwardUnconditionalBranchTargets; + + private LinkedList<Branch> reverseUnconditionalBranchTargets; + + private Instruction firstChild = null; + + private Instruction lastChild = null; + + public void setChildren(Instruction _firstChild, Instruction _lastChild) { + + if ((_firstChild == null) || (_lastChild == null)) { + throw new IllegalStateException("null children added"); + } + firstChild = _firstChild; + lastChild = _lastChild; + + for (Instruction i = firstChild; i != lastChild; i = i.getNextExpr()) { + if (i == null) { + throw new IllegalStateException("child list broken "); + } + i.setParentExpr(this); + } + lastChild.setParentExpr(this); + } + + public Instruction getPrevExpr() { + return (prevExpr); + + } + + public Instruction getNextExpr() { + return (nextExpr); + } + + public void setNextPC(Instruction _nextByPC) { + nextPC = _nextByPC; + } + + public void setPrevPC(Instruction _prevByPC) { + prevPC = _prevByPC; + } + + public void setPrevExpr(Instruction _prevExpr) { + prevExpr = _prevExpr; + } + + public void setNextExpr(Instruction _nextExpr) { + nextExpr = _nextExpr; + } + + public Instruction toInstruction() { + return (this); + } + + public int getLength() { + return (length); + } + + public void setLength(int _length) { + length = _length; + } + + public final ByteCode getByteCode() { + return (byteCode); + } + + public int getThisPC() { + return (pc); + } + + public int getStartPC() { + return (getFirstChild() == null ? pc : getFirstChild().getStartPC()); + } + + protected Instruction(MethodModel _method, ByteCode _byteCode, int _pc) { + method = _method; + pc = _pc; + byteCode = _byteCode; + } + + protected Instruction(MethodModel _method, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + this(_method, _byteCode, _wide ? _byteReader.getOffset() - 2 : _byteReader.getOffset() - 1); + } + + // This works for most cases (except calls whose operand count depends upon the signature) so all call instructions therefore override this method + public int getStackConsumeCount() { + return (byteCode.getPop().getStackAdjust()); + } + + public int getStackProduceCount() { + return (byteCode.getPush().getStackAdjust()); + } + + public int getStackDelta() { + return (getStackProduceCount() - getStackConsumeCount()); + } + + @Override public String toString() { + return pc + " " + byteCode.getName(); + } + + public boolean isBranch() { + return (this instanceof Branch); + } + + public int compareTo(Instruction _other) { + return (pc - _other.pc); + } + + public boolean isAfter(Instruction _other) { + return (compareTo(_other) > 0); + } + + public boolean isAfterOrEqual(Instruction _other) { + return (compareTo(_other) >= 0); + } + + public boolean isBefore(Instruction _other) { + return (compareTo(_other) < 0); + } + + public boolean isBeforeOrEqual(Instruction _other) { + return (compareTo(_other) <= 0); + } + + public Instruction getFirstChild() { + return (firstChild); + } + + public Instruction getLastChild() { + return (lastChild); + } + + public Instruction getStartInstruction() { + return (getFirstChild() == null ? this : getFirstChild().getStartInstruction()); + } + + public MethodModel getMethod() { + return (method); + } + + public Instruction getNextPC() { + return (nextPC); + } + + public Instruction getPrevPC() { + return (prevPC); + } + + public void setParentExpr(Instruction _parentExpr) { + parentExpr = _parentExpr; + } + + public Instruction getParentExpr() { + return (parentExpr); + } + + public Instruction getRootExpr() { + return (parentExpr == null ? this : parentExpr.getRootExpr()); + } + + public boolean isReverseConditionalBranchTarget() { + return ((reverseConditionalBranchTargets != null) && (reverseConditionalBranchTargets.size() > 0)); + } + + public boolean isForwardConditionalBranchTarget() { + return ((forwardConditionalBranchTargets != null) && (forwardConditionalBranchTargets.size() > 0)); + } + + public boolean isReverseUnconditionalBranchTarget() { + return ((reverseUnconditionalBranchTargets != null) && (reverseUnconditionalBranchTargets.size() > 0)); + } + + public boolean isForwardUnconditionalBranchTarget() { + return ((forwardUnconditionalBranchTargets != null) && (forwardUnconditionalBranchTargets.size() > 0)); + } + + public boolean isReverseBranchTarget() { + return (isReverseConditionalBranchTarget() || isReverseUnconditionalBranchTarget()); + } + + public boolean isConditionalBranchTarget() { + return (isReverseConditionalBranchTarget() || isForwardConditionalBranchTarget()); + } + + public boolean isUnconditionalBranchTarget() { + return (isReverseUnconditionalBranchTarget() || isForwardUnconditionalBranchTarget()); + } + + public boolean isForwardBranchTarget() { + return (isForwardConditionalBranchTarget() || isForwardUnconditionalBranchTarget()); + } + + public boolean isBranchTarget() { + return (isForwardBranchTarget() || isReverseBranchTarget()); + } + + public boolean producesStack() { + return ((this instanceof CompositeInstruction) || (getStackProduceCount() > 0)); + } + + public Instruction getReal() { + return (this); + } + + public Branch asBranch() { + return ((Branch) this); + } + + public boolean consumesStack() { + return (getStackConsumeCount() > 0); + } + + public void addBranchTarget(Branch _branch) { + + if (_branch.isReverse()) { + if (_branch.isConditional()) { + if (reverseConditionalBranchTargets == null) { + reverseConditionalBranchTargets = new LinkedList<ConditionalBranch>(); + } + reverseConditionalBranchTargets.add((ConditionalBranch) _branch); + } else { + if (reverseUnconditionalBranchTargets == null) { + reverseUnconditionalBranchTargets = new LinkedList<Branch>(); + } + reverseUnconditionalBranchTargets.add(_branch); + } + } else { + if (_branch.isConditional()) { + if (forwardConditionalBranchTargets == null) { + forwardConditionalBranchTargets = new LinkedList<ConditionalBranch>(); + } + forwardConditionalBranchTargets.add((ConditionalBranch) _branch); + } else { + if (forwardUnconditionalBranchTargets == null) { + forwardUnconditionalBranchTargets = new LinkedList<Branch>(); + } + forwardUnconditionalBranchTargets.add(_branch); + } + } + } + + public void removeBranchTarget(Branch _branch) { + if (_branch.isReverse()) { + if (_branch.isConditional()) { + if (reverseConditionalBranchTargets != null) { + reverseConditionalBranchTargets.remove(_branch); + if (reverseConditionalBranchTargets.size() == 0) { + reverseConditionalBranchTargets = null; + } + } + } else { + if (reverseUnconditionalBranchTargets != null) { + reverseUnconditionalBranchTargets.remove(_branch); + if (reverseUnconditionalBranchTargets.size() == 0) { + reverseUnconditionalBranchTargets = null; + } + } + } + } else { + if (_branch.isConditional()) { + if (forwardConditionalBranchTargets != null) { + forwardConditionalBranchTargets.remove(_branch); + if (forwardConditionalBranchTargets.size() == 0) { + forwardConditionalBranchTargets = null; + } + } + } else { + if (forwardUnconditionalBranchTargets != null) { + forwardUnconditionalBranchTargets.remove(_branch); + if (forwardUnconditionalBranchTargets.size() == 0) { + forwardUnconditionalBranchTargets = null; + } + } + } + } + } + + public LinkedList<Branch> getForwardUnconditionalBranches() { + return (forwardUnconditionalBranchTargets); + } + + public LinkedList<ConditionalBranch> getForwardConditionalBranches() { + return (forwardConditionalBranchTargets); + } + + public LinkedList<Branch> getReverseUnconditionalBranches() { + return (reverseUnconditionalBranchTargets); + } + + public LinkedList<ConditionalBranch> getReverseConditionalBranches() { + return (reverseConditionalBranchTargets); + } + + public boolean isForwardBranch() { + return (isBranch() && asBranch().isForward()); + } + + public boolean sameAs(Instruction _other) { + return (equals(_other)); + } +} diff --git a/src/main/java/com/aparapi/internal/instruction/InstructionPattern.java b/src/main/java/com/aparapi/internal/instruction/InstructionPattern.java index 019f9686d7692cce303ae2a7e649e079f0ef45f8..c0ad9ac97a0183cc1021f4db95a0fefe51a27e85 100644 --- a/src/main/java/com/aparapi/internal/instruction/InstructionPattern.java +++ b/src/main/java/com/aparapi/internal/instruction/InstructionPattern.java @@ -1,500 +1,500 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.instruction; - -import com.aparapi.internal.instruction.InstructionSet.AccessArrayElement; -import com.aparapi.internal.instruction.InstructionSet.AccessInstanceField; -import com.aparapi.internal.instruction.InstructionSet.AccessLocalVariable; -import com.aparapi.internal.instruction.InstructionSet.AssignToArrayElement; -import com.aparapi.internal.instruction.InstructionSet.AssignToInstanceField; -import com.aparapi.internal.instruction.InstructionSet.AssignToLocalVariable; -import com.aparapi.internal.instruction.InstructionSet.CastOperator; -import com.aparapi.internal.instruction.InstructionSet.Constant; -import com.aparapi.internal.instruction.InstructionSet.I_IADD; -import com.aparapi.internal.instruction.InstructionSet.I_ICONST_1; -import com.aparapi.internal.instruction.InstructionSet.I_IINC; -import com.aparapi.internal.instruction.InstructionSet.I_ISUB; -import com.aparapi.internal.instruction.InstructionSet.MethodCall; - -public class InstructionPattern{ - - @SuppressWarnings("unused") private boolean compareSubTrees(Instruction _lhs, Instruction _rhs) { - _lhs = _lhs.getReal(); - _rhs = _rhs.getReal(); - boolean same = _lhs.sameAs(_rhs); - if (same) { - Instruction lhsChild = _lhs.getFirstChild(); - Instruction rhsChild = _rhs.getFirstChild(); - while (same && (lhsChild != null) && (rhsChild != null)) { - same = same && compareSubTrees(lhsChild, rhsChild); - if (same) { - rhsChild = rhsChild.getNextExpr(); - lhsChild = lhsChild.getNextExpr(); - } - } - same = same && (lhsChild == rhsChild); - - } - return (same); - } - - public static class InstructionMatch{ - public final boolean ok; - - public static final InstructionMatch TRUE = new InstructionMatch(true); - - public static final InstructionMatch FALSE = new InstructionMatch(false); - - public InstructionMatch(boolean _ok) { - ok = _ok; - } - - public static InstructionMatch test(boolean _condition) { - return (_condition ? TRUE : FALSE); - } - } - - public static abstract class InstructionMatcher{ - - private final String description; - - abstract InstructionMatch matches(Instruction _instruction); - - public InstructionMatch matches(Instruction _instruction, InstructionMatcher _instructionMatcher) { - if (matches(_instruction.getReal()).ok) { - if (_instruction.getNextExpr() != null) { - return (_instructionMatcher.matches(_instruction.getNextExpr().getReal())); - } - } - - return (InstructionMatch.FALSE); - } - - public InstructionMatcher(String _description) { - description = _description; - } - - public String getDescription() { - return (description); - } - } - - public class AssignableInstructionMatcher extends InstructionMatcher{ - private final Class<?>[] classes; - - public AssignableInstructionMatcher(Class<?>... _classes) { - super("AssignableInstructionMatcher"); - classes = _classes; - } - - @Override public InstructionMatch matches(Instruction _instruction) { - for (final Class<?> c : classes) { - if (c.isAssignableFrom(_instruction.getClass())) { - return (InstructionMatch.TRUE); - - } - } - - return (InstructionMatch.TRUE); - } - } - - public static final InstructionMatcher assignToLocalVariable = new InstructionMatcher("Assign to local variable"){ - @Override public InstructionMatch matches(Instruction _instruction) { - return (InstructionMatch.test(_instruction instanceof AssignToLocalVariable)); - } - }; - - public static final InstructionMatcher constant = new InstructionMatcher("Constant "){ - @Override public InstructionMatch matches(Instruction _instruction) { - return (InstructionMatch.test(_instruction instanceof Constant<?>)); - } - }; - - public static final InstructionMatcher assignToArrayElement = new InstructionMatcher("Assign to array element"){ - @Override public InstructionMatch matches(Instruction _instruction) { - return (InstructionMatch.test(_instruction instanceof AssignToArrayElement)); - } - }; - - public static final InstructionMatcher methodCall = new InstructionMatcher("Method Call"){ - @Override public InstructionMatch matches(Instruction _instruction) { - return (InstructionMatch.test(_instruction instanceof MethodCall)); - } - }; - - public static final InstructionMatcher longHandIncLocalVariable = new InstructionMatcher("Long hand increment of local variable"){ - /** - * <pre> - * - * / iload<n> - * istore<n> - iadd - * \ i_const_1 - * - * / iload<n> - * istore<n> - (?2i) - iadd - * \ i_const_1 - * - * </pre> - */ - @Override public InstructionMatch matches(Instruction _instruction) { - if (_instruction instanceof AssignToLocalVariable) { - final AssignToLocalVariable assign = (AssignToLocalVariable) _instruction; - Instruction child = ((Instruction) assign).getFirstChild(); - - if (child instanceof CastOperator) { - child = child.getFirstChild(); - } - - if (child instanceof I_IADD) { - final I_IADD add = (I_IADD) child; - final Instruction lhs = add.getLhs(); - final Instruction rhs = add.getRhs(); - if (lhs instanceof AccessLocalVariable) { - final AccessLocalVariable access = (AccessLocalVariable) lhs; - if (access.getLocalVariableTableIndex() == assign.getLocalVariableTableIndex()) { - if (rhs instanceof I_ICONST_1) { - return (InstructionMatch.TRUE); - } - } - } - } - } - - return (InstructionMatch.FALSE); - } - }; - - public static final InstructionMatcher longHandDecLocalVariable = new InstructionMatcher("Long hand decrement of local variable"){ - /** - * <pre> - * - * / iload<n> - * istore<n> - isub - * \ i_const_1 - * - * / iload<n> - * istore<n> - (?2i) - isub - * \ i_const_1 - * - * </pre> - */ - @Override public InstructionMatch matches(Instruction _instruction) { - if (_instruction instanceof AssignToLocalVariable) { - final AssignToLocalVariable assign = (AssignToLocalVariable) _instruction; - Instruction child = ((Instruction) assign).getFirstChild(); - - if (child instanceof CastOperator) { - child = child.getFirstChild(); - } - - if (child instanceof I_ISUB) { - final I_ISUB add = (I_ISUB) child; - final Instruction lhs = add.getLhs(); - final Instruction rhs = add.getRhs(); - if (lhs instanceof AccessLocalVariable) { - final AccessLocalVariable access = (AccessLocalVariable) lhs; - if (access.getLocalVariableTableIndex() == assign.getLocalVariableTableIndex()) { - if (rhs instanceof I_ICONST_1) { - return (InstructionMatch.TRUE); - } - } - } - } - } - - return (InstructionMatch.FALSE); - } - }; - - public static final InstructionMatcher fieldPlusOne = new InstructionMatcher("Field Plus One"){ - /** - * <pre> - * / getfield<f> - * i2<t> iadd - * \ i_const_1 - * - * / getfield<f> - * iadd - * \ i_const_1 - * </pre> - */ - @Override public InstructionMatch matches(Instruction _instruction) { - - if (_instruction instanceof CastOperator) { - final CastOperator topCastOperator = (CastOperator) _instruction; - _instruction = topCastOperator.getFirstChild().getReal(); - } - - if (_instruction instanceof I_IADD) { - final I_IADD add = (I_IADD) _instruction; - final Instruction addLhs = add.getLhs().getReal(); - final Instruction addRhs = add.getRhs().getReal(); - if (addLhs instanceof AccessInstanceField) { - if (addRhs instanceof I_ICONST_1) { - return (InstructionMatch.TRUE); - } - } - } - - return (InstructionMatch.FALSE); - } - }; - - public static final InstructionMatcher fieldMinusOne = new InstructionMatcher("Field minus 1"){ - /** - * <pre> - * / getfield<f> - * i2<t> isub - * \ i_const_1 - * - * / getfield<f> - * isub - * \ i_const_1 - * </pre> - */ - @Override public InstructionMatch matches(Instruction _instruction) { - - if (_instruction instanceof CastOperator) { - final CastOperator topCastOperator = (CastOperator) _instruction; - _instruction = topCastOperator.getFirstChild().getReal(); - } - - if (_instruction instanceof I_ISUB) { - final I_ISUB add = (I_ISUB) _instruction; - final Instruction addLhs = add.getLhs().getReal(); - final Instruction addRhs = add.getRhs().getReal(); - if (addLhs instanceof AccessInstanceField) { - if (addRhs instanceof I_ICONST_1) { - return (InstructionMatch.TRUE); - } - } - } - - return (InstructionMatch.FALSE); - } - }; - - public static final InstructionMatcher fieldArrayElementAccess = new InstructionMatcher("Field array element access"){ - /** - * - * <pre> - * - * / getfield<f> - * iaload - * \ i_load - * </pre> - */ - @Override public InstructionMatch matches(Instruction _instruction) { - if (_instruction instanceof AccessArrayElement) { - final AccessArrayElement accessArrayElement = (AccessArrayElement) _instruction; - final Instruction addLhs = accessArrayElement.getArrayRef().getReal(); - // Instruction addRhs = accessArrayElement.getArrayIndex().getReal(); - if (addLhs instanceof AccessInstanceField) { - - return (InstructionMatch.TRUE); - - } - } - - return (InstructionMatch.FALSE); - } - }; - - public static final InstructionMatcher fieldArrayElementPlusOne = new InstructionMatcher("field array element plus one"){ - /** - * <pre> - * [ / getfield - aload_0 ] - * / [fieldArrayElementAccess][ iaload ] - * iadd [ \ iload ] - * \ iconst_1 - * </pre> - */ - @Override public InstructionMatch matches(Instruction _instruction) { - if (_instruction instanceof I_IADD) { - final I_IADD accessArrayElement = (I_IADD) _instruction; - if (accessArrayElement.getLhs() != null) { - final Instruction addLhs = accessArrayElement.getLhs().getReal(); - if (fieldArrayElementAccess.matches(addLhs).ok) { - final Instruction addRhs = accessArrayElement.getRhs().getReal(); - if (addRhs instanceof I_ICONST_1) { - return (InstructionMatch.TRUE); - } - } - } - } - - return (InstructionMatch.FALSE); - } - }; - - public static final InstructionMatcher fieldArrayElementMinusOne = new InstructionMatcher("field array element minus one"){ - /** - * <pre> - * [ / getfield - aload_0 ] - * / [fieldArrayElementAccess][ iaload ] - * isub [ \ iload ] - * \ iconst_1 - * </pre> - */ - @Override public InstructionMatch matches(Instruction _instruction) { - if (_instruction instanceof I_ISUB) { - final I_ISUB accessArrayElement = (I_ISUB) _instruction; - final Instruction addLhs = accessArrayElement.getLhs().getReal(); - if (fieldArrayElementAccess.matches(addLhs).ok) { - final Instruction addRhs = accessArrayElement.getRhs().getReal(); - if (addRhs instanceof I_ICONST_1) { - return (InstructionMatch.TRUE); - } - } - } - - return (InstructionMatch.FALSE); - } - }; - - public static final InstructionMatcher longHandFieldArrayElementIncrement = new InstructionMatcher( - "long hand field array element increment"){ - /** - * //iastore{9:getfield{8:aload_0} ,12:iload_1 ,17:iadd{14:iaload{*9:getfield{8:aload_0} ,*12:iload_1} ,16:iconst_1}} - * <pre> - * - * / getfield - aload - * iastore - iload - * \ [fieldArrayElementPlusOne] - * </pre> - */ - @Override public InstructionMatch matches(Instruction _instruction) { - if (_instruction instanceof AssignToArrayElement) { - final AssignToArrayElement accessArrayElement = (AssignToArrayElement) _instruction; - final Instruction arrayRef = accessArrayElement.getArrayRef().getReal(); - // Instruction arrayIndex = accessArrayElement.getArrayIndex().getReal(); - final Instruction value = accessArrayElement.getValue().getReal(); - - // Instruction addRhs = accessArrayElement.getArrayIndex().getReal(); - if (arrayRef instanceof AccessInstanceField) { - if (fieldArrayElementPlusOne.matches(value).ok) { - return (InstructionMatch.TRUE); - } - } - } - - return (InstructionMatch.FALSE); - } - }; - - public static final InstructionMatcher longHandFieldArrayElementDecrement = new InstructionMatcher( - "long hand field array element decrement"){ - /** - * //iastore{9:getfield{8:aload_0} ,12:iload_1 ,17:iadd{14:iaload{*9:getfield{8:aload_0} ,*12:iload_1} ,16:iconst_1}} - * <pre> - * - * / getfield - aload - * iastore - iload - * \ [fieldArrayElementPlusOne] - * </pre> - */ - @Override public InstructionMatch matches(Instruction _instruction) { - if (_instruction instanceof AssignToArrayElement) { - final AssignToArrayElement accessArrayElement = (AssignToArrayElement) _instruction; - final Instruction arrayRef = accessArrayElement.getArrayRef().getReal(); - // Instruction arrayIndex = accessArrayElement.getArrayIndex().getReal(); - final Instruction value = accessArrayElement.getValue().getReal(); - // Instruction addRhs = accessArrayElement.getArrayIndex().getReal(); - if (arrayRef instanceof AccessInstanceField) { - if (fieldArrayElementMinusOne.matches(value).ok) { - return (InstructionMatch.TRUE); - } - } - } - - return (InstructionMatch.FALSE); - } - }; - - public static final InstructionMatcher accessLocalVariable = new InstructionMatcher("access to local variable"){ - @Override InstructionMatch matches(Instruction _instruction) { - return (InstructionMatch.test(_instruction instanceof AccessLocalVariable)); - } - }; - - public static final InstructionMatcher inc = new InstructionMatcher("inc"){ - @Override InstructionMatch matches(Instruction _instruction) { - return (InstructionMatch.test(_instruction instanceof I_IINC)); - } - }; - - public static final InstructionMatcher cast = new InstructionMatcher("cast"){ - @Override InstructionMatch matches(Instruction _instruction) { - return (InstructionMatch.test(_instruction instanceof CastOperator)); - } - }; - - public static final InstructionMatcher accessInstanceField = new InstructionMatcher("access instance field"){ - @Override InstructionMatch matches(Instruction _instruction) { - return (InstructionMatch.test(_instruction instanceof AccessInstanceField)); - } - }; - - public static final InstructionMatcher assignToInstanceField = new InstructionMatcher("assign to instance field"){ - @Override InstructionMatch matches(Instruction _instruction) { - return (InstructionMatch.test(_instruction instanceof AssignToInstanceField)); - } - }; - - public static final InstructionMatcher iadd = new InstructionMatcher("iadd"){ - @Override InstructionMatch matches(Instruction _instruction) { - return (InstructionMatch.test(_instruction instanceof I_IADD)); - } - }; -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.instruction; + +import com.aparapi.internal.instruction.InstructionSet.AccessArrayElement; +import com.aparapi.internal.instruction.InstructionSet.AccessInstanceField; +import com.aparapi.internal.instruction.InstructionSet.AccessLocalVariable; +import com.aparapi.internal.instruction.InstructionSet.AssignToArrayElement; +import com.aparapi.internal.instruction.InstructionSet.AssignToInstanceField; +import com.aparapi.internal.instruction.InstructionSet.AssignToLocalVariable; +import com.aparapi.internal.instruction.InstructionSet.CastOperator; +import com.aparapi.internal.instruction.InstructionSet.Constant; +import com.aparapi.internal.instruction.InstructionSet.I_IADD; +import com.aparapi.internal.instruction.InstructionSet.I_ICONST_1; +import com.aparapi.internal.instruction.InstructionSet.I_IINC; +import com.aparapi.internal.instruction.InstructionSet.I_ISUB; +import com.aparapi.internal.instruction.InstructionSet.MethodCall; + +public class InstructionPattern{ + + @SuppressWarnings("unused") private boolean compareSubTrees(Instruction _lhs, Instruction _rhs) { + _lhs = _lhs.getReal(); + _rhs = _rhs.getReal(); + boolean same = _lhs.sameAs(_rhs); + if (same) { + Instruction lhsChild = _lhs.getFirstChild(); + Instruction rhsChild = _rhs.getFirstChild(); + while (same && (lhsChild != null) && (rhsChild != null)) { + same = same && compareSubTrees(lhsChild, rhsChild); + if (same) { + rhsChild = rhsChild.getNextExpr(); + lhsChild = lhsChild.getNextExpr(); + } + } + same = same && (lhsChild == rhsChild); + + } + return (same); + } + + public static class InstructionMatch{ + public final boolean ok; + + public static final InstructionMatch TRUE = new InstructionMatch(true); + + public static final InstructionMatch FALSE = new InstructionMatch(false); + + public InstructionMatch(boolean _ok) { + ok = _ok; + } + + public static InstructionMatch test(boolean _condition) { + return (_condition ? TRUE : FALSE); + } + } + + public static abstract class InstructionMatcher{ + + private final String description; + + abstract InstructionMatch matches(Instruction _instruction); + + public InstructionMatch matches(Instruction _instruction, InstructionMatcher _instructionMatcher) { + if (matches(_instruction.getReal()).ok) { + if (_instruction.getNextExpr() != null) { + return (_instructionMatcher.matches(_instruction.getNextExpr().getReal())); + } + } + + return (InstructionMatch.FALSE); + } + + public InstructionMatcher(String _description) { + description = _description; + } + + public String getDescription() { + return (description); + } + } + + public class AssignableInstructionMatcher extends InstructionMatcher{ + private final Class<?>[] classes; + + public AssignableInstructionMatcher(Class<?>... _classes) { + super("AssignableInstructionMatcher"); + classes = _classes; + } + + @Override public InstructionMatch matches(Instruction _instruction) { + for (final Class<?> c : classes) { + if (c.isAssignableFrom(_instruction.getClass())) { + return (InstructionMatch.TRUE); + + } + } + + return (InstructionMatch.TRUE); + } + } + + public static final InstructionMatcher assignToLocalVariable = new InstructionMatcher("Assign to local variable"){ + @Override public InstructionMatch matches(Instruction _instruction) { + return (InstructionMatch.test(_instruction instanceof AssignToLocalVariable)); + } + }; + + public static final InstructionMatcher constant = new InstructionMatcher("Constant "){ + @Override public InstructionMatch matches(Instruction _instruction) { + return (InstructionMatch.test(_instruction instanceof Constant<?>)); + } + }; + + public static final InstructionMatcher assignToArrayElement = new InstructionMatcher("Assign to array element"){ + @Override public InstructionMatch matches(Instruction _instruction) { + return (InstructionMatch.test(_instruction instanceof AssignToArrayElement)); + } + }; + + public static final InstructionMatcher methodCall = new InstructionMatcher("Method Call"){ + @Override public InstructionMatch matches(Instruction _instruction) { + return (InstructionMatch.test(_instruction instanceof MethodCall)); + } + }; + + public static final InstructionMatcher longHandIncLocalVariable = new InstructionMatcher("Long hand increment of local variable"){ + /** + * <pre> + * + * / iload<n> + * istore<n> - iadd + * \ i_const_1 + * + * / iload<n> + * istore<n> - (?2i) - iadd + * \ i_const_1 + * + * </pre> + */ + @Override public InstructionMatch matches(Instruction _instruction) { + if (_instruction instanceof AssignToLocalVariable) { + final AssignToLocalVariable assign = (AssignToLocalVariable) _instruction; + Instruction child = ((Instruction) assign).getFirstChild(); + + if (child instanceof CastOperator) { + child = child.getFirstChild(); + } + + if (child instanceof I_IADD) { + final I_IADD add = (I_IADD) child; + final Instruction lhs = add.getLhs(); + final Instruction rhs = add.getRhs(); + if (lhs instanceof AccessLocalVariable) { + final AccessLocalVariable access = (AccessLocalVariable) lhs; + if (access.getLocalVariableTableIndex() == assign.getLocalVariableTableIndex()) { + if (rhs instanceof I_ICONST_1) { + return (InstructionMatch.TRUE); + } + } + } + } + } + + return (InstructionMatch.FALSE); + } + }; + + public static final InstructionMatcher longHandDecLocalVariable = new InstructionMatcher("Long hand decrement of local variable"){ + /** + * <pre> + * + * / iload<n> + * istore<n> - isub + * \ i_const_1 + * + * / iload<n> + * istore<n> - (?2i) - isub + * \ i_const_1 + * + * </pre> + */ + @Override public InstructionMatch matches(Instruction _instruction) { + if (_instruction instanceof AssignToLocalVariable) { + final AssignToLocalVariable assign = (AssignToLocalVariable) _instruction; + Instruction child = ((Instruction) assign).getFirstChild(); + + if (child instanceof CastOperator) { + child = child.getFirstChild(); + } + + if (child instanceof I_ISUB) { + final I_ISUB add = (I_ISUB) child; + final Instruction lhs = add.getLhs(); + final Instruction rhs = add.getRhs(); + if (lhs instanceof AccessLocalVariable) { + final AccessLocalVariable access = (AccessLocalVariable) lhs; + if (access.getLocalVariableTableIndex() == assign.getLocalVariableTableIndex()) { + if (rhs instanceof I_ICONST_1) { + return (InstructionMatch.TRUE); + } + } + } + } + } + + return (InstructionMatch.FALSE); + } + }; + + public static final InstructionMatcher fieldPlusOne = new InstructionMatcher("Field Plus One"){ + /** + * <pre> + * / getfield<f> + * i2<t> iadd + * \ i_const_1 + * + * / getfield<f> + * iadd + * \ i_const_1 + * </pre> + */ + @Override public InstructionMatch matches(Instruction _instruction) { + + if (_instruction instanceof CastOperator) { + final CastOperator topCastOperator = (CastOperator) _instruction; + _instruction = topCastOperator.getFirstChild().getReal(); + } + + if (_instruction instanceof I_IADD) { + final I_IADD add = (I_IADD) _instruction; + final Instruction addLhs = add.getLhs().getReal(); + final Instruction addRhs = add.getRhs().getReal(); + if (addLhs instanceof AccessInstanceField) { + if (addRhs instanceof I_ICONST_1) { + return (InstructionMatch.TRUE); + } + } + } + + return (InstructionMatch.FALSE); + } + }; + + public static final InstructionMatcher fieldMinusOne = new InstructionMatcher("Field minus 1"){ + /** + * <pre> + * / getfield<f> + * i2<t> isub + * \ i_const_1 + * + * / getfield<f> + * isub + * \ i_const_1 + * </pre> + */ + @Override public InstructionMatch matches(Instruction _instruction) { + + if (_instruction instanceof CastOperator) { + final CastOperator topCastOperator = (CastOperator) _instruction; + _instruction = topCastOperator.getFirstChild().getReal(); + } + + if (_instruction instanceof I_ISUB) { + final I_ISUB add = (I_ISUB) _instruction; + final Instruction addLhs = add.getLhs().getReal(); + final Instruction addRhs = add.getRhs().getReal(); + if (addLhs instanceof AccessInstanceField) { + if (addRhs instanceof I_ICONST_1) { + return (InstructionMatch.TRUE); + } + } + } + + return (InstructionMatch.FALSE); + } + }; + + public static final InstructionMatcher fieldArrayElementAccess = new InstructionMatcher("Field array element access"){ + /** + * + * <pre> + * + * / getfield<f> + * iaload + * \ i_load + * </pre> + */ + @Override public InstructionMatch matches(Instruction _instruction) { + if (_instruction instanceof AccessArrayElement) { + final AccessArrayElement accessArrayElement = (AccessArrayElement) _instruction; + final Instruction addLhs = accessArrayElement.getArrayRef().getReal(); + // Instruction addRhs = accessArrayElement.getArrayIndex().getReal(); + if (addLhs instanceof AccessInstanceField) { + + return (InstructionMatch.TRUE); + + } + } + + return (InstructionMatch.FALSE); + } + }; + + public static final InstructionMatcher fieldArrayElementPlusOne = new InstructionMatcher("field array element plus one"){ + /** + * <pre> + * [ / getfield - aload_0 ] + * / [fieldArrayElementAccess][ iaload ] + * iadd [ \ iload ] + * \ iconst_1 + * </pre> + */ + @Override public InstructionMatch matches(Instruction _instruction) { + if (_instruction instanceof I_IADD) { + final I_IADD accessArrayElement = (I_IADD) _instruction; + if (accessArrayElement.getLhs() != null) { + final Instruction addLhs = accessArrayElement.getLhs().getReal(); + if (fieldArrayElementAccess.matches(addLhs).ok) { + final Instruction addRhs = accessArrayElement.getRhs().getReal(); + if (addRhs instanceof I_ICONST_1) { + return (InstructionMatch.TRUE); + } + } + } + } + + return (InstructionMatch.FALSE); + } + }; + + public static final InstructionMatcher fieldArrayElementMinusOne = new InstructionMatcher("field array element minus one"){ + /** + * <pre> + * [ / getfield - aload_0 ] + * / [fieldArrayElementAccess][ iaload ] + * isub [ \ iload ] + * \ iconst_1 + * </pre> + */ + @Override public InstructionMatch matches(Instruction _instruction) { + if (_instruction instanceof I_ISUB) { + final I_ISUB accessArrayElement = (I_ISUB) _instruction; + final Instruction addLhs = accessArrayElement.getLhs().getReal(); + if (fieldArrayElementAccess.matches(addLhs).ok) { + final Instruction addRhs = accessArrayElement.getRhs().getReal(); + if (addRhs instanceof I_ICONST_1) { + return (InstructionMatch.TRUE); + } + } + } + + return (InstructionMatch.FALSE); + } + }; + + public static final InstructionMatcher longHandFieldArrayElementIncrement = new InstructionMatcher( + "long hand field array element increment"){ + /** + * //iastore{9:getfield{8:aload_0} ,12:iload_1 ,17:iadd{14:iaload{*9:getfield{8:aload_0} ,*12:iload_1} ,16:iconst_1}} + * <pre> + * + * / getfield - aload + * iastore - iload + * \ [fieldArrayElementPlusOne] + * </pre> + */ + @Override public InstructionMatch matches(Instruction _instruction) { + if (_instruction instanceof AssignToArrayElement) { + final AssignToArrayElement accessArrayElement = (AssignToArrayElement) _instruction; + final Instruction arrayRef = accessArrayElement.getArrayRef().getReal(); + // Instruction arrayIndex = accessArrayElement.getArrayIndex().getReal(); + final Instruction value = accessArrayElement.getValue().getReal(); + + // Instruction addRhs = accessArrayElement.getArrayIndex().getReal(); + if (arrayRef instanceof AccessInstanceField) { + if (fieldArrayElementPlusOne.matches(value).ok) { + return (InstructionMatch.TRUE); + } + } + } + + return (InstructionMatch.FALSE); + } + }; + + public static final InstructionMatcher longHandFieldArrayElementDecrement = new InstructionMatcher( + "long hand field array element decrement"){ + /** + * //iastore{9:getfield{8:aload_0} ,12:iload_1 ,17:iadd{14:iaload{*9:getfield{8:aload_0} ,*12:iload_1} ,16:iconst_1}} + * <pre> + * + * / getfield - aload + * iastore - iload + * \ [fieldArrayElementPlusOne] + * </pre> + */ + @Override public InstructionMatch matches(Instruction _instruction) { + if (_instruction instanceof AssignToArrayElement) { + final AssignToArrayElement accessArrayElement = (AssignToArrayElement) _instruction; + final Instruction arrayRef = accessArrayElement.getArrayRef().getReal(); + // Instruction arrayIndex = accessArrayElement.getArrayIndex().getReal(); + final Instruction value = accessArrayElement.getValue().getReal(); + // Instruction addRhs = accessArrayElement.getArrayIndex().getReal(); + if (arrayRef instanceof AccessInstanceField) { + if (fieldArrayElementMinusOne.matches(value).ok) { + return (InstructionMatch.TRUE); + } + } + } + + return (InstructionMatch.FALSE); + } + }; + + public static final InstructionMatcher accessLocalVariable = new InstructionMatcher("access to local variable"){ + @Override InstructionMatch matches(Instruction _instruction) { + return (InstructionMatch.test(_instruction instanceof AccessLocalVariable)); + } + }; + + public static final InstructionMatcher inc = new InstructionMatcher("inc"){ + @Override InstructionMatch matches(Instruction _instruction) { + return (InstructionMatch.test(_instruction instanceof I_IINC)); + } + }; + + public static final InstructionMatcher cast = new InstructionMatcher("cast"){ + @Override InstructionMatch matches(Instruction _instruction) { + return (InstructionMatch.test(_instruction instanceof CastOperator)); + } + }; + + public static final InstructionMatcher accessInstanceField = new InstructionMatcher("access instance field"){ + @Override InstructionMatch matches(Instruction _instruction) { + return (InstructionMatch.test(_instruction instanceof AccessInstanceField)); + } + }; + + public static final InstructionMatcher assignToInstanceField = new InstructionMatcher("assign to instance field"){ + @Override InstructionMatch matches(Instruction _instruction) { + return (InstructionMatch.test(_instruction instanceof AssignToInstanceField)); + } + }; + + public static final InstructionMatcher iadd = new InstructionMatcher("iadd"){ + @Override InstructionMatch matches(Instruction _instruction) { + return (InstructionMatch.test(_instruction instanceof I_IADD)); + } + }; +} diff --git a/src/main/java/com/aparapi/internal/instruction/InstructionSet.java b/src/main/java/com/aparapi/internal/instruction/InstructionSet.java index 61510ec287e57ff79c0caa8a0534f23ff37bb4bb..b16536aba98ee95e944ebcfbb4e6730343b6c239 100644 --- a/src/main/java/com/aparapi/internal/instruction/InstructionSet.java +++ b/src/main/java/com/aparapi/internal/instruction/InstructionSet.java @@ -1,3950 +1,3950 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.instruction; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -import com.aparapi.internal.model.MethodModel; -import com.aparapi.internal.model.ClassModel.ConstantPool; -import com.aparapi.internal.model.ClassModel.ConstantPool.Entry; -import com.aparapi.internal.model.ClassModel.ConstantPool.FieldEntry; -import com.aparapi.internal.model.ClassModel.ConstantPool.MethodEntry; -import com.aparapi.internal.model.ClassModel.LocalVariableTableEntry; -import com.aparapi.internal.model.ClassModel.LocalVariableInfo; -import com.aparapi.internal.reader.ByteReader; - -public class InstructionSet{ - - public static enum LoadSpec { - NONE, // - F, // Float - D, // Double - I, // Integer - L, // Long - A, // Array - O, // Object - } - - public static enum StoreSpec { - NONE, // - F, // Float - D, // Double - I, // Integer - L, // Long - A, // Array - O, // Object - } - - public static enum TypeSpec { - NONE("none", "none", 0, 0), // - Z("Z", "boolean", 4, 1), // Note 'Z' is the java code for 'boolean' type - C("C", "char", 2, 1), // - F("F", "float", 4, 1), // - D("D", "double", 8, 2), // - B("B", "byte", 1, 1), // - S("S", "short", 2, 1), // - I("I", "int", 4, 1), // - L("L", "long", 8, 1), // - J("J", "long", 8, 1), // Note J is the java code for 'long' type - A("A", "array", 4, 1), // - O("O", "object", 4, 1), - N("N", "null", 4, 1), - IorForS("IorForS", "int, float or String depending on constant pool entry", 4, 1), - LorD("LorD", "long or float depending upon the constant pool entry", 8, 2), - RA("RA", "return address", 4, 1), - UNKNOWN("UNKNOWN", "unknown", -1, -1), - ARGS("ARGS", "args to method call", -1, -1); - - private final String longName; - - private final String shortName; - - private final int size; - - private final int slots; - - private TypeSpec(String _shortName, String _longName, int _size, int _slots) { - shortName = _shortName; - longName = _longName; - size = _size; - slots = _slots; - } - - public int getSize() { - return (size); - } - - public int getSlots() { - return (slots); - } - - public String getLongName() { - return (longName); - } - - public String getShortName() { - return (shortName); - } - } - - /** - * Represents an Operator - * - * @author gfrost - * - */ - - public static enum Operator { - NONE, - LogicalOr(true, "||"), // - LogicalAnd(true, "&&", LogicalOr), // - Equal(true, "=="), // - NotEqual(true, "!=", Equal), // - LessThan(true, "<"), // - GreaterThanOrEqual(true, ">=", LessThan), // - GreaterThan(true, ">"), // - LessThanOrEqual(true, "<=", GreaterThan), // - EqualNULL(true, "NULL=="), - NotEqualNULL(true, "NULL!=", EqualNULL), // - - BitwiseOr(true, "|"), // - BitwiseAnd(true, "&"), // - BitwiseXor(true, "^"), - - LeftShift(true, "<<"), // - ArithmeticRightShift(true, ">>>"), // - LogicalRightShift(true, ">>"), // was >>> but this caused issues in opencl - - Add(true, "+"), // - Sub(true, "-"), // - - Div(true, "/"), // - Rem(true, "%"), // - Mul(true, "*"), // - - Neg(false, "-"), // - Pos(false, "+"), // - - I2FCast(false, "(float)"), - I2LCast(false, "(long)"), // - I2DCast(false, "(double)"), // - L2ICast(false, "(int)"), // - L2FCast(false, "(float)"), // - L2DCast(false, "(double)"), // - F2ICast(false, "(int)"), // - F2LCast(false, "(long)"), // - F2DCast(false, "(double)"), // - D2ICast(false, "(int)"), // - D2LCast(false, "(long)"), // - D2FCast(false, "(float)"), // - I2BCast(false, "(byte)"), // - I2CCast(false, "(char)"), // - I2SCast(false, "(short)"); - - private final String text; - - private final boolean binary; - - private Operator compliment; - - private Operator(boolean _binary, String _text) { - - text = _text; - binary = _binary; - } - - private Operator(boolean _binary, String _text, Operator _c) { - this(_binary, _text); - compliment = _c; - compliment.compliment = this; - } - - private Operator() { - this(false, null); - } - - public String getText() { - return text; - } - - public Operator getCompliment() { - return (compliment); - } - - public String getText(boolean _invert) { - return (_invert ? compliment.getText() : getText()); - } - - public boolean isBinary() { - return (binary); - - } - - public boolean isUnary() { - return (!equals(Operator.NONE) && !isBinary()); - - } - } - - public static enum PushSpec { - NONE, // - UNKNOWN, // - I(TypeSpec.I), // - II(TypeSpec.I, TypeSpec.I), // - III(TypeSpec.I, TypeSpec.I, TypeSpec.I), // - IIII(TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I), // - IIIII(TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I), // - IIIIII(TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I), // - L(TypeSpec.L), // - F(TypeSpec.F), // - D(TypeSpec.D), // - O(TypeSpec.O), // - A(TypeSpec.A), // - N(TypeSpec.N), // - IorForS(TypeSpec.IorForS), // - LorD(TypeSpec.LorD), // - RA(TypeSpec.RA); - - private PushSpec(TypeSpec... _types) { - types = _types; - } - - private final TypeSpec[] types; - - public int getStackAdjust() { - return (types.length); - } - } - - public static enum PopSpec { - NONE, // - UNKNOWN(TypeSpec.UNKNOWN), // - I(TypeSpec.I), // - II(TypeSpec.I, TypeSpec.I), // - III(TypeSpec.I, TypeSpec.I, TypeSpec.I), // - IIII(TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I), // - IIIII(TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I), // - L(TypeSpec.L), // - LL(TypeSpec.L, TypeSpec.L), // - F(TypeSpec.F), // - FF(TypeSpec.F, TypeSpec.F), // - D(TypeSpec.D), // - DD(TypeSpec.D, TypeSpec.D), // - O(TypeSpec.O), // - OO(TypeSpec.O, TypeSpec.O), // - A(TypeSpec.A), // - AI(TypeSpec.A, TypeSpec.I), // - AII(TypeSpec.A, TypeSpec.I, TypeSpec.I), // - AIF(TypeSpec.A, TypeSpec.I, TypeSpec.F), // - AID(TypeSpec.A, TypeSpec.I, TypeSpec.D), // - AIL(TypeSpec.A, TypeSpec.I, TypeSpec.L), // - AIC(TypeSpec.A, TypeSpec.I, TypeSpec.C), // - AIS(TypeSpec.A, TypeSpec.I, TypeSpec.S), // - AIB(TypeSpec.A, TypeSpec.I, TypeSpec.B), // - AIO(TypeSpec.A, TypeSpec.I, TypeSpec.O), // - LI(TypeSpec.L, TypeSpec.I), // - OUNKNOWN(TypeSpec.O, TypeSpec.UNKNOWN), // - ARGS(TypeSpec.ARGS), // - OARGS(TypeSpec.O, TypeSpec.ARGS), // - ; - - private PopSpec(TypeSpec... _types) { - types = _types; - } - - private final TypeSpec[] types; - - public int getStackAdjust() { - return (types.length); - } - } - - public static enum ImmediateSpec { - NONE("NONE"), // - UNKNOWN("UNKNOWN"), // - Bconst("byte constant value", TypeSpec.B), // - Sconst("short constant value", TypeSpec.S), // - Bcpci("byte constant pool constant index", TypeSpec.B), // - Scpci("short constant pool constant index", TypeSpec.S), // - Icpci("int constant pool index", TypeSpec.I), // - Blvti("byte local variable table index", TypeSpec.B), - Spc("short pc", TypeSpec.S), - Ipc("int pc", TypeSpec.I), - Scpfi("short constant pool field index", TypeSpec.S), - Scpmi("short constant pool method index", TypeSpec.S), - ScpmiBB("short constant pool method index, byte count, byte (always zero)", TypeSpec.S, TypeSpec.B, TypeSpec.B), - ScpciBdim("short constant pool class index, byte dimensions", TypeSpec.S, TypeSpec.B), - BlvtiBconst("byte local variable table index, byte constant value", TypeSpec.B, TypeSpec.B); - - private final String name; - - private ImmediateSpec(String _name, TypeSpec... _types) { - - name = _name; - types = _types; - } - - private final TypeSpec[] types; - - public String getName() { - return (name); - } - - public TypeSpec[] getTypes() { - return (types); - } - } - - public static enum ByteCode { - // name, operation type, immediateOperands, pop operands, push operands - NOP(null, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, PopSpec.NONE, PushSpec.NONE, Operator.NONE), // - ACONST_NULL(I_ACONST_NULL.class, PushSpec.N), // - ICONST_M1(I_ICONST_M1.class, PushSpec.I), // - ICONST_0(I_ICONST_0.class, PushSpec.I), // - ICONST_1(I_ICONST_1.class, PushSpec.I), // - ICONST_2(I_ICONST_2.class, PushSpec.I), // - ICONST_3(I_ICONST_3.class, PushSpec.I), // - ICONST_4(I_ICONST_4.class, PushSpec.I), // - ICONST_5(I_ICONST_5.class, PushSpec.I), // - LCONST_0(I_LCONST_0.class, PushSpec.L), // - LCONST_1(I_LCONST_1.class, PushSpec.L), // - FCONST_0(I_FCONST_0.class, PushSpec.F), // - FCONST_1(I_FCONST_1.class, PushSpec.F), // - FCONST_2(I_FCONST_2.class, PushSpec.F), // - DCONST_0(I_DCONST_0.class, PushSpec.D), // - DCONST_1(I_DCONST_1.class, PushSpec.D), // - BIPUSH(I_BIPUSH.class, ImmediateSpec.Bconst, PushSpec.I), // - SIPUSH(I_SIPUSH.class, ImmediateSpec.Sconst, PushSpec.I), // - LDC(I_LDC.class, ImmediateSpec.Bcpci, PushSpec.IorForS), // - LDC_W(I_LDC_W.class, ImmediateSpec.Scpci, PushSpec.IorForS), // - LDC2_W(I_LDC2_W.class, ImmediateSpec.Scpci, PushSpec.LorD), // - ILOAD(I_ILOAD.class, LoadSpec.I, ImmediateSpec.Blvti, PushSpec.I), // - LLOAD(I_LLOAD.class, LoadSpec.L, ImmediateSpec.Blvti, PushSpec.L), // - FLOAD(I_FLOAD.class, LoadSpec.F, ImmediateSpec.Blvti, PushSpec.F), // - DLOAD(I_DLOAD.class, LoadSpec.F, ImmediateSpec.Blvti, PushSpec.D), // - ALOAD(I_ALOAD.class, LoadSpec.A, ImmediateSpec.Blvti, PushSpec.O), // - ILOAD_0(I_ILOAD_0.class, LoadSpec.I, PushSpec.I), // - ILOAD_1(I_ILOAD_1.class, LoadSpec.I, PushSpec.I), // - ILOAD_2(I_ILOAD_2.class, LoadSpec.I, PushSpec.I), // - ILOAD_3(I_ILOAD_3.class, LoadSpec.I, PushSpec.I), // - LLOAD_0(I_LLOAD_0.class, LoadSpec.L, PushSpec.L), // - LLOAD_1(I_LLOAD_1.class, LoadSpec.L, PushSpec.L), // - LLOAD_2(I_LLOAD_2.class, LoadSpec.L, PushSpec.L), // - LLOAD_3(I_LLOAD_3.class, LoadSpec.L, PushSpec.L), // - FLOAD_0(I_FLOAD_0.class, LoadSpec.F, PushSpec.F), // - FLOAD_1(I_FLOAD_1.class, LoadSpec.F, PushSpec.F), // - FLOAD_2(I_FLOAD_2.class, LoadSpec.F, PushSpec.F), // - FLOAD_3(I_FLOAD_3.class, LoadSpec.F, PushSpec.F), // - DLOAD_0(I_DLOAD_0.class, LoadSpec.D, PushSpec.D), // - DLOAD_1(I_DLOAD_1.class, LoadSpec.D, PushSpec.D), // - DLOAD_2(I_DLOAD_2.class, LoadSpec.D, PushSpec.D), // - DLOAD_3(I_DLOAD_3.class, LoadSpec.D, PushSpec.D), // - ALOAD_0(I_ALOAD_0.class, LoadSpec.A, PushSpec.O), // - ALOAD_1(I_ALOAD_1.class, LoadSpec.A, PushSpec.O), // - ALOAD_2(I_ALOAD_2.class, LoadSpec.A, PushSpec.O), // - ALOAD_3(I_ALOAD_3.class, LoadSpec.A, PushSpec.O), // - IALOAD(I_IALOAD.class, PopSpec.AI, PushSpec.I), // - LALOAD(I_LALOAD.class, PopSpec.AI, PushSpec.L), // - FALOAD(I_FALOAD.class, PopSpec.AI, PushSpec.F), // - DALOAD(I_DALOAD.class, PopSpec.AI, PushSpec.D), // - AALOAD(I_AALOAD.class, PopSpec.AI, PushSpec.A), // - BALOAD(I_BALOAD.class, PopSpec.AI, PushSpec.I), // - CALOAD(I_CALOAD.class, PopSpec.AI, PushSpec.I), // - SALOAD(I_SALOAD.class, PopSpec.AI, PushSpec.I), // - ISTORE(I_ISTORE.class, StoreSpec.I, ImmediateSpec.Blvti, PopSpec.I), // - LSTORE(I_LSTORE.class, StoreSpec.L, ImmediateSpec.Blvti, PopSpec.L), // - FSTORE(I_FSTORE.class, StoreSpec.F, ImmediateSpec.Blvti, PopSpec.F), // - DSTORE(I_DSTORE.class, StoreSpec.D, ImmediateSpec.Blvti, PopSpec.D), // - ASTORE(I_ASTORE.class, StoreSpec.A, ImmediateSpec.Blvti, PopSpec.O), // - ISTORE_0(I_ISTORE_0.class, StoreSpec.I, PopSpec.I), // - ISTORE_1(I_ISTORE_1.class, StoreSpec.I, PopSpec.I), // - ISTORE_2(I_ISTORE_2.class, StoreSpec.I, PopSpec.I), // - ISTORE_3(I_ISTORE_3.class, StoreSpec.I, PopSpec.I), // - LSTORE_0(I_LSTORE_0.class, StoreSpec.L, PopSpec.L), // - LSTORE_1(I_LSTORE_1.class, StoreSpec.L, PopSpec.L), // - LSTORE_2(I_LSTORE_2.class, StoreSpec.L, PopSpec.L), // - LSTORE_3(I_LSTORE_3.class, StoreSpec.L, PopSpec.L), // - FSTORE_0(I_FSTORE_0.class, StoreSpec.F, PopSpec.F), // - FSTORE_1(I_FSTORE_1.class, StoreSpec.F, PopSpec.F), // - FSTORE_2(I_FSTORE_2.class, StoreSpec.F, PopSpec.F), // - FSTORE_3(I_FSTORE_3.class, StoreSpec.F, PopSpec.F), // - DSTORE_0(I_DSTORE_0.class, StoreSpec.D, PopSpec.D), // - DSTORE_1(I_DSTORE_1.class, StoreSpec.D, PopSpec.D), // - DSTORE_2(I_DSTORE_2.class, StoreSpec.D, PopSpec.D), // - DSTORE_3(I_DSTORE_3.class, StoreSpec.D, PopSpec.D), // - ASTORE_0(I_ASTORE_0.class, StoreSpec.A, PopSpec.O), // - ASTORE_1(I_ASTORE_1.class, StoreSpec.A, PopSpec.O), // - ASTORE_2(I_ASTORE_2.class, StoreSpec.A, PopSpec.O), // - ASTORE_3(I_ASTORE_3.class, StoreSpec.A, PopSpec.O), // - IASTORE(I_IASTORE.class, PopSpec.AII), // - LASTORE(I_LASTORE.class, PopSpec.AIL), // - FASTORE(I_FASTORE.class, PopSpec.AIF), // - DASTORE(I_DASTORE.class, PopSpec.AID), // - AASTORE(I_AASTORE.class, PopSpec.AIO), // - BASTORE(I_BASTORE.class, PopSpec.AIB), // - CASTORE(I_CASTORE.class, PopSpec.AIC), // - SASTORE(I_SASTORE.class, PopSpec.AIS), // - POP(I_POP.class, PopSpec.I), // - POP2(I_POP2.class, PopSpec.II), // - DUP(I_DUP.class, PopSpec.I, PushSpec.II), // - DUP_X1(I_DUP_X1.class, PopSpec.II, PushSpec.III), // - DUP_X2(I_DUP_X2.class, PopSpec.III, PushSpec.IIII), // - DUP2(I_DUP2.class, PopSpec.II, PushSpec.IIII), // - DUP2_X1(I_DUP2_X1.class, PopSpec.III, PushSpec.IIIII), // - DUP2_X2(I_DUP2_X2.class, PopSpec.IIII, PushSpec.IIIIII), // - SWAP(I_SWAP.class, PopSpec.II, PushSpec.II), // ..., value2, value1 => ..., value1, - // value2 - IADD(I_IADD.class, PopSpec.II, PushSpec.I, Operator.Add), // - LADD(I_LADD.class, PopSpec.LL, PushSpec.L, Operator.Add), // - FADD(I_FADD.class, PopSpec.FF, PushSpec.F, Operator.Add), // - DADD(I_DADD.class, PopSpec.DD, PushSpec.D, Operator.Add), // - ISUB(I_ISUB.class, PopSpec.II, PushSpec.I, Operator.Sub), // - LSUB(I_LSUB.class, PopSpec.LL, PushSpec.L, Operator.Sub), // - FSUB(I_FSUB.class, PopSpec.FF, PushSpec.F, Operator.Sub), // - DSUB(I_DSUB.class, PopSpec.DD, PushSpec.D, Operator.Sub), // - IMUL(I_IMUL.class, PopSpec.II, PushSpec.I, Operator.Mul), // - LMUL(I_LMUL.class, PopSpec.LL, PushSpec.L, Operator.Mul), // - FMUL(I_FMUL.class, PopSpec.FF, PushSpec.F, Operator.Mul), // - DMUL(I_DMUL.class, PopSpec.DD, PushSpec.D, Operator.Mul), // - IDIV(I_IDIV.class, PopSpec.II, PushSpec.I, Operator.Div), // - LDIV(I_LDIV.class, PopSpec.LL, PushSpec.L, Operator.Div), // - FDIV(I_FDIV.class, PopSpec.FF, PushSpec.F, Operator.Div), // - DDIV(I_DDIV.class, PopSpec.DD, PushSpec.D, Operator.Div), // - IREM(I_IREM.class, PopSpec.II, PushSpec.I, Operator.Rem), // - LREM(I_LREM.class, PopSpec.LL, PushSpec.L, Operator.Rem), // - FREM(I_FREM.class, PopSpec.FF, PushSpec.F, Operator.Rem), // - DREM(I_DREM.class, PopSpec.DD, PushSpec.D, Operator.Rem), // - INEG(I_INEG.class, PopSpec.I, PushSpec.I, Operator.Neg), // - LNEG(I_LNEG.class, PopSpec.L, PushSpec.L, Operator.Neg), // - FNEG(I_FNEG.class, PopSpec.F, PushSpec.F, Operator.Neg), // - DNEG(I_DNEG.class, PopSpec.D, PushSpec.D, Operator.Neg), // - ISHL(I_ISHL.class, PopSpec.II, PushSpec.I, Operator.LeftShift), // - LSHL(I_LSHL.class, PopSpec.LI, PushSpec.L, Operator.LeftShift), // - ISHR(I_ISHR.class, PopSpec.II, PushSpec.I, Operator.LogicalRightShift), // - LSHR(I_LSHR.class, PopSpec.LI, PushSpec.L, Operator.LogicalRightShift), // - IUSHR(I_IUSHR.class, PopSpec.II, PushSpec.I, Operator.ArithmeticRightShift), // - LUSHR(I_LUSHR.class, PopSpec.LI, PushSpec.L, Operator.ArithmeticRightShift), // - IAND(I_IAND.class, PopSpec.II, PushSpec.I, Operator.BitwiseAnd), // - LAND(I_LAND.class, PopSpec.LL, PushSpec.L, Operator.BitwiseAnd), // - IOR(I_IOR.class, PopSpec.II, PushSpec.I, Operator.BitwiseOr), // - LOR(I_LOR.class, PopSpec.LL, PushSpec.L, Operator.BitwiseOr), // - IXOR(I_IXOR.class, PopSpec.II, PushSpec.I, Operator.BitwiseXor), // - LXOR(I_LXOR.class, PopSpec.LL, PushSpec.L, Operator.BitwiseXor), // - IINC(I_IINC.class, ImmediateSpec.BlvtiBconst), // - I2L(I_I2L.class, PopSpec.I, PushSpec.L, Operator.I2LCast), // - I2F(I_I2F.class, PopSpec.I, PushSpec.F, Operator.I2FCast), // - I2D(I_I2D.class, PopSpec.I, PushSpec.D, Operator.I2DCast), // - L2I(I_L2I.class, PopSpec.L, PushSpec.I, Operator.L2ICast), // - L2F(I_L2F.class, PopSpec.L, PushSpec.F, Operator.L2FCast), // - L2D(I_L2D.class, PopSpec.L, PushSpec.D, Operator.L2DCast), // - F2I(I_F2I.class, PopSpec.F, PushSpec.I, Operator.F2ICast), // - F2L(I_F2L.class, PopSpec.F, PushSpec.L, Operator.F2LCast), // - F2D(I_F2D.class, PopSpec.F, PushSpec.D, Operator.F2DCast), // - D2I(I_D2I.class, PopSpec.D, PushSpec.I, Operator.D2ICast), // - D2L(I_D2L.class, PopSpec.D, PushSpec.L, Operator.D2LCast), // - D2F(I_D2F.class, PopSpec.D, PushSpec.F, Operator.D2FCast), // - I2B(I_I2B.class, PopSpec.I, PushSpec.I, Operator.I2BCast), // - I2C(I_I2C.class, PopSpec.I, PushSpec.I, Operator.I2CCast), // - I2S(I_I2S.class, PopSpec.I, PushSpec.I, Operator.I2SCast), // - LCMP(I_LCMP.class, PopSpec.LL, PushSpec.I, Operator.Sub), // - FCMPL(I_FCMPL.class, PopSpec.FF, PushSpec.I, Operator.LessThan), // - FCMPG(I_FCMPG.class, PopSpec.FF, PushSpec.I, Operator.GreaterThan), // - DCMPL(I_DCMPL.class, PopSpec.DD, PushSpec.I, Operator.LessThan), // - DCMPG(I_DCMPG.class, PopSpec.DD, PushSpec.I, Operator.GreaterThan), // - IFEQ(I_IFEQ.class, ImmediateSpec.Spc, PopSpec.I, Operator.Equal), // - IFNE(I_IFNE.class, ImmediateSpec.Spc, PopSpec.I, Operator.NotEqual), // - IFLT(I_IFLT.class, ImmediateSpec.Spc, PopSpec.I, Operator.LessThan), // - IFGE(I_IFGE.class, ImmediateSpec.Spc, PopSpec.I, Operator.GreaterThanOrEqual), // - IFGT(I_IFGT.class, ImmediateSpec.Spc, PopSpec.I, Operator.GreaterThan), // - IFLE(I_IFLE.class, ImmediateSpec.Spc, PopSpec.I, Operator.LessThanOrEqual), // - IF_ICMPEQ(I_IF_ICMPEQ.class, ImmediateSpec.Sconst, PopSpec.II, Operator.Equal), // - IF_ICMPNE(I_IF_ICMPNE.class, ImmediateSpec.Spc, PopSpec.II, Operator.NotEqual), // - IF_ICMPLT(I_IF_ICMPLT.class, ImmediateSpec.Spc, PopSpec.II, Operator.LessThan), // - IF_ICMPGE(I_IF_ICMPGE.class, ImmediateSpec.Spc, PopSpec.II, Operator.GreaterThanOrEqual), // - IF_ICMPGT(I_IF_ICMPGT.class, ImmediateSpec.Spc, PopSpec.II, Operator.GreaterThan), // - IF_ICMPLE(I_IF_ICMPLE.class, ImmediateSpec.Spc, PopSpec.II, Operator.LessThanOrEqual), // - IF_ACMPEQ(I_IF_ACMPEQ.class, ImmediateSpec.Spc, PopSpec.OO, Operator.Equal), // - IF_ACMPNE(I_IF_ACMPNE.class, ImmediateSpec.Spc, PopSpec.OO, Operator.NotEqual), // - GOTO(I_GOTO.class, ImmediateSpec.Spc), // - JSR(I_JSR.class, ImmediateSpec.Spc, PushSpec.RA), // - RET(I_RET.class, ImmediateSpec.Bconst), // - TABLESWITCH(I_TABLESWITCH.class, ImmediateSpec.UNKNOWN, PopSpec.I), // - LOOKUPSWITCH(I_LOOKUPSWITCH.class, ImmediateSpec.UNKNOWN, PopSpec.I), // - IRETURN(I_IRETURN.class, PopSpec.I), // - LRETURN(I_LRETURN.class, PopSpec.L), // - FRETURN(I_FRETURN.class, PopSpec.F), // - DRETURN(I_DRETURN.class, PopSpec.D), // - ARETURN(I_ARETURN.class, PopSpec.O), // - RETURN(I_RETURN.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, PopSpec.NONE, PushSpec.NONE, Operator.NONE), // - GETSTATIC(I_GETSTATIC.class, ImmediateSpec.Scpfi, PushSpec.UNKNOWN), // - PUTSTATIC(I_PUTSTATIC.class, ImmediateSpec.Scpfi, PopSpec.UNKNOWN), // - GETFIELD(I_GETFIELD.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpfi, PopSpec.O, PushSpec.UNKNOWN, Operator.NONE), // - PUTFIELD(I_PUTFIELD.class, ImmediateSpec.Scpfi, PopSpec.OUNKNOWN), // - INVOKEVIRTUAL(I_INVOKEVIRTUAL.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpmi, PopSpec.OARGS, PushSpec.UNKNOWN, - Operator.NONE), // - INVOKESPECIAL(I_INVOKESPECIAL.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpmi, PopSpec.OARGS, PushSpec.UNKNOWN, - Operator.NONE), // - INVOKESTATIC(I_INVOKESTATIC.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpmi, PopSpec.ARGS, PushSpec.UNKNOWN, - Operator.NONE), // - INVOKEINTERFACE(I_INVOKEINTERFACE.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.ScpmiBB, PopSpec.OARGS, - PushSpec.UNKNOWN, Operator.NONE), // - INVOKEDYNAMIC(I_INVOKEDYNAMIC.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.ScpmiBB, PopSpec.OARGS, PushSpec.UNKNOWN, - Operator.NONE), // - - NEW(I_NEW.class, ImmediateSpec.Scpci, PushSpec.O), // - NEWARRAY(I_NEWARRAY.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Bconst, PopSpec.I, PushSpec.A, Operator.NONE), // - ANEWARRAY(I_ANEWARRAY.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Sconst, PopSpec.I, PushSpec.A, Operator.NONE), // 189 - ARRAYLENGTH(I_ARRAYLENGTH.class, PopSpec.A, PushSpec.I), // 190 - ATHROW(I_ATHROW.class, PopSpec.O, PushSpec.O), // 191 - CHECKCAST(I_CHECKCAST.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpci, PopSpec.O, PushSpec.O, Operator.NONE), // 192 - INSTANCEOF(I_INSTANCEOF.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpci, PopSpec.O, PushSpec.I, Operator.NONE), // 193 - MONITORENTER(I_MONITORENTER.class, PopSpec.O), // 194 - MONITOREXIT(I_MONITOREXIT.class, PopSpec.O), // 195 - WIDE(I_WIDE.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.UNKNOWN, PopSpec.UNKNOWN, PushSpec.UNKNOWN, Operator.NONE), // 196 - MULTIANEWARRAY(I_MULTIANEWARRAY.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.ScpciBdim, PopSpec.UNKNOWN, PushSpec.A, - Operator.NONE), // 197 - IFNULL(I_IFNULL.class, ImmediateSpec.Spc, PopSpec.O, Operator.EqualNULL), // 198 - IFNONNULL(I_IFNONNULL.class, ImmediateSpec.Spc, PopSpec.O, Operator.NotEqualNULL), // 199 - GOTO_W(I_GOTO_W.class, ImmediateSpec.Ipc), // 200 - JSR_W(I_JSR_W.class, ImmediateSpec.Ipc, PushSpec.RA), // 201 - ILLEGAL_202, // BREAKPOINT("breakpoint"), - ILLEGAL_203, // LDC_QUICK("ldc_quick"), - ILLEGAL_204, // LDC_W_QUICK("ldc_w_quick"), - ILLEGAL_205, // LDC2_W_QUICK("ldc2_w_quick"), - ILLEGAL_206, // GETFIELD_QUICK("getfield_quick"), - ILLEGAL_207, // PUTFIELD_QUICK("putfield_quick"), - ILLEGAL_208, // GETFIELD2_QUICK("getfield2_quick"), - ILLEGAL_209, // PUTFIELD2_QUICK("putfield2_quick"), - ILLEGAL_210, // GETSTATIC_QUICK("getstatic_quick"), - ILLEGAL_211, // PUTSTATIC_QUICK("putstatic_quick"), - ILLEGAL_212, // GETSTATIC2_QUICK("getstatic2_quick"), - ILLEGAL_213, // PUTSTATIC2_QUICK("putstatic2_quick"), - ILLEGAL_214, // INVOKEVIRTUAL_QUICK("invokevirtual_quick"), - ILLEGAL_215, // INVOKENONVIRTUAL_QUICK("invokenonvirtual_quick"), - ILLEGAL_216, // INVOKESUPER_QUICK("invokesuper_quick"), - ILLEGAL_217, // INVOKESTATIC_QUICK("invokestatic_quick"), - ILLEGAL_218, // INVOKEINTERFACE_QUICK("invokeinterface_quick"), - ILLEGAL_219, // INVOKEVIRTUALOBJECT_QUICK("invokevirtualobject_quick"), - ILLEGAL_220, // 220 - ILLEGAL_221, // NEW_QUICK("new_quick"), - ILLEGAL_222, // ANEWARRAY_QUICK("anewarray_quick"), - ILLEGAL_223, // MULTIANEWARRAY_QUICK("multianewarray_quick"), - ILLEGAL_224, // CHECKCAST_QUICK("checkcast_quick"), - ILLEGAL_225, // INSTANCEOF_QUICK("instanceof_quick"), - ILLEGAL_226, // INVOKEVIRTUAL_QUICK_W("invokevirtual_quick_w"), - ILLEGAL_227, // GETFIELD_QUICK_W("getfield_quick_w"), - ILLEGAL_228, // PUTFIELD_QUICK_W("putfield_quick_w"), - ILLEGAL_229, // - ILLEGAL_230, // - ILLEGAL_231, // - ILLEGAL_232, // - ILLEGAL_233, // - ILLEGAL_234, // - ILLEGAL_235, // - ILLEGAL_236, // - ILLEGAL_237, // - ILLEGAL_238, // - ILLEGAL_239, // - ILLEGAL_240, // - ILLEGAL_241, // - ILLEGAL_242, // - ILLEGAL_243, // - ILLEGAL_244, // - ILLEGAL_245, // - ILLEGAL_246, // - ILLEGAL_247, // - ILLEGAL_248, // - ILLEGAL_249, // - ILLEGAL_250, // - ILLEGAL_251, // - ILLEGAL_252, // - ILLEGAL_253, // - ILLEGAL_254, // IMPDEP1("impdep1"), - ILLEGAL_255, // IMPDEP2("impdep2"), - NONE, // - COMPOSITE_IF, // - COMPOSITE_IF_ELSE, // - COMPOSITE_FOR_SUN, // - COMPOSITE_FOR_ECLIPSE, // - COMPOSITE_ARBITRARY_SCOPE, // - COMPOSITE_WHILE, // - CLONE, // - INCREMENT, // - INLINE_ASSIGN, // - MULTI_ASSIGN, // - FAKEGOTO, // - FIELD_ARRAY_ELEMENT_INCREMENT, // - FIELD_ARRAY_ELEMENT_ASSIGN, // - HEAD, // - COMPOSITE_EMPTY_LOOP, // - COMPOSITE_DO_WHILE; - - private final Class<?> clazz; - - private final ImmediateSpec immediate; - - private final PushSpec push; - - private final PopSpec pop; - - private final Operator operator; - - private LoadSpec loadSpec; - - private StoreSpec storeSpec; - - private Constructor<?> constructor; - - private ByteCode(Class<?> _class, LoadSpec _loadSpec, StoreSpec _storeSpec, ImmediateSpec _immediate, PopSpec _pop, - PushSpec _push, Operator _operator) { - clazz = _class; - immediate = _immediate; - push = _push; - pop = _pop; - operator = _operator; - - loadSpec = _loadSpec; - storeSpec = _storeSpec; - if (clazz != null) { - - try { - constructor = clazz.getDeclaredConstructor(MethodModel.class, ByteReader.class, boolean.class); - } catch (final SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final NoSuchMethodException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - private ByteCode(Class<?> _class, ImmediateSpec _immediate) { - this(_class, LoadSpec.NONE, StoreSpec.NONE, _immediate, PopSpec.NONE, PushSpec.NONE, Operator.NONE); - } - - private ByteCode(Class<?> _class, PushSpec _push) { - this(_class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, PopSpec.NONE, _push, Operator.NONE); - } - - private ByteCode(Class<?> _class, StoreSpec _store, ImmediateSpec _immediate, PopSpec _pop) { - this(_class, LoadSpec.NONE, _store, _immediate, _pop, PushSpec.NONE, Operator.NONE); - } - - private ByteCode(Class<?> _class, StoreSpec _store, PopSpec _pop) { - this(_class, LoadSpec.NONE, _store, ImmediateSpec.NONE, _pop, PushSpec.NONE, Operator.NONE); - } - - private ByteCode(Class<?> _class, ImmediateSpec _immediate, PopSpec _pop) { - this(_class, LoadSpec.NONE, StoreSpec.NONE, _immediate, _pop, PushSpec.NONE, Operator.NONE); - } - - private ByteCode(Class<?> _class, ImmediateSpec _immediate, PopSpec _pop, Operator _operator) { - this(_class, LoadSpec.NONE, StoreSpec.NONE, _immediate, _pop, PushSpec.NONE, _operator); - } - - private ByteCode(Class<?> _class, LoadSpec _load, ImmediateSpec _immediate, PushSpec _push) { - this(_class, _load, StoreSpec.NONE, _immediate, PopSpec.NONE, _push, Operator.NONE); - } - - private ByteCode(Class<?> _class, LoadSpec _load, PushSpec _push) { - this(_class, _load, StoreSpec.NONE, ImmediateSpec.NONE, PopSpec.NONE, _push, Operator.NONE); - } - - private ByteCode(Class<?> _class, ImmediateSpec _immediate, PushSpec _push) { - this(_class, LoadSpec.NONE, StoreSpec.NONE, _immediate, PopSpec.NONE, _push, Operator.NONE); - } - - private ByteCode(Class<?> _class, PopSpec _pop, PushSpec _push) { - this(_class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, _pop, _push, Operator.NONE); - } - - private ByteCode(Class<?> _class, PopSpec _pop, PushSpec _push, Operator _operator) { - this(_class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, _pop, _push, _operator); - } - - private ByteCode(Class<?> _class, PopSpec _pop) { - this(_class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, _pop, PushSpec.NONE, Operator.NONE); - } - - private ByteCode() { - this(null, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, PopSpec.NONE, PushSpec.NONE, Operator.NONE); - } - - public int getCode() { - return (ordinal()); - } - - public String getName() { - return (name().toLowerCase()); - } - - public ImmediateSpec getImmediate() { - return (immediate); - } - - public static ByteCode get(int _idx) { - return (values()[_idx]); - } - - public PushSpec getPush() { - return (push); - } - - public PopSpec getPop() { - return (pop); - } - - // Note I am intentionally skipping PushSpec.LorD. - public boolean usesDouble() { - final PushSpec push = getPush(); - final PopSpec pop = getPop(); - - if ((push == PushSpec.D) || (pop == PopSpec.D) || (pop == PopSpec.DD) || (pop == PopSpec.AID)) { - return true; - } - - return false; - } - - public Instruction newInstruction(MethodModel _methodModel, ByteReader byteReader, boolean _isWide) { - Instruction newInstruction = null; - if (constructor != null) { - try { - newInstruction = (Instruction) constructor.newInstance(_methodModel, byteReader, _isWide); - newInstruction.setLength(byteReader.getOffset() - newInstruction.getThisPC()); - } catch (final SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InstantiationException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - return (newInstruction); - } - - public static Instruction create(MethodModel _methodModel, ByteReader _byteReader) { - ByteCode byteCode = get(_byteReader.u1()); - boolean isWide = false; - - if (byteCode.equals(ByteCode.WIDE)) { - // handle wide - //System.out.println("WIDE"); - isWide = true; - byteCode = get(_byteReader.u1()); - } - - final Instruction newInstruction = byteCode.newInstruction(_methodModel, _byteReader, isWide); - - return (newInstruction); - } - - public Operator getOperator() { - return (operator); - } - - public LoadSpec getLoad() { - return (loadSpec); - } - - public StoreSpec getStore() { - return (storeSpec); - } - } - - public static class CompositeInstruction extends Instruction{ - - protected BranchSet branchSet; - - public CompositeInstruction(MethodModel method, ByteCode _byteCode, Instruction _firstChild, Instruction _lastChild, - BranchSet _branchSet) { - super(method, _byteCode, -1); - branchSet = _branchSet; - setChildren(_firstChild, _lastChild); - } - - @Override public String getDescription() { - return ("COMPOSITE! " + getByteCode()); - } - - @Override public int getThisPC() { - return (getLastChild().getThisPC()); - } - - @Override public int getStartPC() { - return (getFirstChild().getStartPC()); - } - - public static CompositeInstruction create(ByteCode _byteCode, MethodModel _methodModel, Instruction _firstChild, - Instruction _lastChild, BranchSet _branchSet) { - CompositeInstruction compositeInstruction = null; - switch (_byteCode) { - case COMPOSITE_IF: - compositeInstruction = new CompositeIfInstruction(_methodModel, _firstChild, _lastChild, _branchSet); - break; - case COMPOSITE_IF_ELSE: - compositeInstruction = new CompositeIfElseInstruction(_methodModel, _firstChild, _lastChild, _branchSet); - break; - case COMPOSITE_FOR_SUN: - compositeInstruction = new CompositeForSunInstruction(_methodModel, _firstChild, _lastChild, _branchSet); - break; - case COMPOSITE_WHILE: - compositeInstruction = new CompositeWhileInstruction(_methodModel, _firstChild, _lastChild, _branchSet); - break; - case COMPOSITE_FOR_ECLIPSE: - compositeInstruction = new CompositeForEclipseInstruction(_methodModel, _firstChild, _lastChild, _branchSet); - break; - case COMPOSITE_ARBITRARY_SCOPE: - compositeInstruction = new CompositeArbitraryScopeInstruction(_methodModel, _firstChild, _lastChild, _branchSet); - break; - case COMPOSITE_EMPTY_LOOP: - compositeInstruction = new CompositeEmptyLoopInstruction(_methodModel, _firstChild, _lastChild, _branchSet); - break; - case COMPOSITE_DO_WHILE: - compositeInstruction = new CompositeDoWhileInstruction(_methodModel, _firstChild, _lastChild, _branchSet); - break; - } - - return (compositeInstruction); - } - - public BranchSet getBranchSet() { - return (branchSet); - } - } - - public static class CompositeIfInstruction extends CompositeInstruction{ - public CompositeIfInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, BranchSet _branchSet) { - super(method, ByteCode.COMPOSITE_IF, _firstChild, _lastChild, _branchSet); - } - } - - public static class CompositeIfElseInstruction extends CompositeInstruction{ - public CompositeIfElseInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, BranchSet _branchSet) { - super(method, ByteCode.COMPOSITE_IF_ELSE, _firstChild, _lastChild, _branchSet); - } - } - - public static class CompositeForSunInstruction extends CompositeInstruction{ - public CompositeForSunInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, BranchSet _branchSet) { - super(method, ByteCode.COMPOSITE_FOR_SUN, _firstChild, _lastChild, _branchSet); - } - } - - public static class CompositeWhileInstruction extends CompositeInstruction{ - public CompositeWhileInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, BranchSet _branchSet) { - super(method, ByteCode.COMPOSITE_WHILE, _firstChild, _lastChild, _branchSet); - } - } - - public static class CompositeEmptyLoopInstruction extends CompositeInstruction{ - public CompositeEmptyLoopInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, BranchSet _branchSet) { - super(method, ByteCode.COMPOSITE_EMPTY_LOOP, _firstChild, _lastChild, _branchSet); - } - } - - public static class CompositeDoWhileInstruction extends CompositeInstruction{ - - protected CompositeDoWhileInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, - BranchSet _branchSet) { - super(method, ByteCode.COMPOSITE_DO_WHILE, _firstChild, _lastChild, _branchSet); - } - } - - public static class CompositeForEclipseInstruction extends CompositeInstruction{ - protected CompositeForEclipseInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, - BranchSet _branchSet) { - super(method, ByteCode.COMPOSITE_FOR_ECLIPSE, _firstChild, _lastChild, _branchSet); - - } - } - - public static class CompositeArbitraryScopeInstruction extends CompositeInstruction{ - protected CompositeArbitraryScopeInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, - BranchSet _branchSet) { - super(method, ByteCode.COMPOSITE_ARBITRARY_SCOPE, _firstChild, _lastChild, _branchSet); - } - } - - public static abstract class OperatorInstruction extends Instruction{ - protected OperatorInstruction(MethodModel _methodPoolEntry, ByteCode code, ByteReader reader, boolean _wide) { - super(_methodPoolEntry, code, reader, _wide); - } - - public Operator getOperator() { - return (getByteCode().getOperator()); - } - } - - public static abstract class BinaryOperator extends OperatorInstruction implements Binary{ - @Override public final Instruction getLhs() { - return (getFirstChild()); - } - - @Override public final Instruction getRhs() { - return (getLastChild()); - } - - protected BinaryOperator(MethodModel _methodPoolEntry, ByteCode code, ByteReader reader, boolean _wide) { - super(_methodPoolEntry, code, reader, _wide); - } - } - - public static abstract class UnaryOperator extends OperatorInstruction implements Unary{ - @Override public final Instruction getUnary() { - return (getFirstChild()); - } - - protected UnaryOperator(MethodModel _methodPoolEntry, ByteCode code, ByteReader reader, boolean _wide) { - super(_methodPoolEntry, code, reader, _wide); - } - } - - public static abstract class CastOperator extends UnaryOperator{ - protected CastOperator(MethodModel _methodPoolEntry, ByteCode code, ByteReader reader, boolean _wide) { - super(_methodPoolEntry, code, reader, _wide); - } - } - - public static abstract class Branch extends Instruction{ - protected int offset; - - protected boolean breakOrContinue; - - protected Instruction target; - - public int getAbsolute() { - return (getThisPC() + getOffset()); - } - - private int getOffset() { - return (offset); - } - - public Branch(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - - public Branch(MethodModel _methodPoolEntry, ByteCode _byteCode, Instruction _target) { - super(_methodPoolEntry, _byteCode, -1); - setTarget(_target); - } - - public Instruction getTarget() { - return (target); - } - - public void setTarget(Instruction _target) { - target = _target; - offset = target.getThisPC() - getThisPC(); - target.addBranchTarget(this); - } - - public boolean isConditional() { - return (this instanceof ConditionalBranch); - } - - public boolean isUnconditional() { - return (this instanceof UnconditionalBranch); - } - - public boolean isReverseConditional() { - return (isConditional() && isReverse()); - } - - public boolean isForwardConditional() { - return (isConditional() && isForward()); - } - - public boolean isReverseUnconditional() { - return (isUnconditional() && isReverse()); - } - - public boolean isForwardUnconditional() { - return (isUnconditional() && isForward()); - } - - public boolean isReverse() { - return (offset < 0); - } - - public boolean isForward() { - return (offset >= 0); - } - - public void unhook() { - getTarget().removeBranchTarget(this); - } - - public void setBreakOrContinue(boolean b) { - breakOrContinue = true; - } - - public boolean isBreakOrContinue() { - return (breakOrContinue); - } - - public void retarget(Instruction _newTarget) { - //System.out.println("retargetting " + pc + " -> " + target.getThisPC() + " to " + _newTarget.getThisPC()); - unhook(); // removes this from the list of branchers to target - setTarget(_newTarget); - //System.out.println("retargetted " + pc + " -> " + target.getThisPC()); - // _newTarget.addBranchTarget(this); - } - } - - public static abstract class ConditionalBranch extends Branch{ - private BranchSet branchSet; - - public ConditionalBranch(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - - public void setBranchSet(BranchSet _branchSet) { - branchSet = _branchSet; - } - - public BranchSet getOrCreateBranchSet() { - if (branchSet == null) { - branchSet = new BranchSet(this); - } - - return branchSet; - } - - public BranchSet getBranchSet() { - return branchSet; - } - - // extent is a guess but we know that the target will be beyond extent, we are not interested in targets that fall before extent - public ConditionalBranch findEndOfConditionalBranchSet(Instruction _extent) { - // bummer ;) - // we need to find the actual branch set. Be careful here we can only create a branch set when we *know* that a conditional is the last in the set. - // we don't know that here. We have to scan forward to try to find it - ConditionalBranch i = this; - Instruction theTarget = null; - ConditionalBranch lastToTarget = null; - - if (getTarget().isAfter(_extent)) { - // if this conditional is already pointing beyond extent then we know the target - theTarget = getTarget(); - lastToTarget = this; - } - - while (i.getNextExpr().isBranch() && i.getNextExpr().asBranch().isForwardConditional()) { - final Branch nextBranch = i.getNextExpr().asBranch(); - - if ((theTarget == null) && nextBranch.getTarget().isAfter(_extent)) { - theTarget = nextBranch.getTarget(); - lastToTarget = this; - } else if (nextBranch.getTarget() == theTarget) { - lastToTarget = this; - } - - i = (ConditionalBranch) i.getNextExpr(); - } - - if (theTarget == null) { - throw new IllegalStateException("unable to find end of while extent"); - } - - return (lastToTarget); - } - } - - public static abstract class UnconditionalBranch extends Branch{ - public UnconditionalBranch(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - - public UnconditionalBranch(MethodModel _methodPoolEntry, ByteCode _byteCode, Instruction _target) { - super(_methodPoolEntry, _byteCode, _target); - } - } - - public static abstract class IfUnary extends ConditionalBranch16 implements Unary{ - public IfUnary(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - - @Override public Instruction getUnary() { - return (getFirstChild()); - } - } - - public static abstract class If extends ConditionalBranch16 implements Binary{ - public If(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - - @Override public Instruction getLhs() { - return (getFirstChild()); - } - - @Override public Instruction getRhs() { - return (getLastChild()); - } - } - - public static abstract class ConditionalBranch16 extends ConditionalBranch implements HasOperator{ - public ConditionalBranch16(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - offset = _byteReader.s2(); - } - - @Override public Operator getOperator() { - return (getByteCode().getOperator()); - } - } - - public static abstract class UnconditionalBranch16 extends UnconditionalBranch{ - public UnconditionalBranch16(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - offset = _byteReader.s2(); - } - } - - public static abstract class Branch32 extends UnconditionalBranch{ - public Branch32(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - offset = _byteReader.s4(); - } - } - - public static abstract class ArrayAccess extends Instruction{ - public ArrayAccess(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - - public Instruction getArrayRef() { - return (getFirstChild()); - } - - public Instruction getArrayIndex() { - return (getFirstChild().getNextExpr()); - } - } - - public static abstract class AccessArrayElement extends ArrayAccess{ - protected AccessArrayElement(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - } - - public static class I_AALOAD extends AccessArrayElement{ - public I_AALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.AALOAD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push reference from arrayref and index"); - } - } - - public static abstract class AssignToArrayElement extends ArrayAccess{ - public Instruction getValue() { - return (getFirstChild().getNextExpr().getNextExpr()); - } - - protected AssignToArrayElement(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - } - - public static class I_AASTORE extends AssignToArrayElement{ - public I_AASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.AASTORE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop reference into arrayref[index]"); - } - } - - public static class I_ACONST_NULL extends Instruction implements Constant<Object>{ - public I_ACONST_NULL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ACONST_NULL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push null"); - } - - @Override public Object getValue() { - return null; - } - } - - public static abstract class LocalVariableConstIndexAccessor extends IndexConst implements AccessLocalVariable{ - public LocalVariableConstIndexAccessor(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide, - int index) { - super(methodPoolEntry, byteCode, byteReader, _wide, index); - } - - @Override public int getLocalVariableTableIndex() { - return (index); - } - - @Override public LocalVariableInfo getLocalVariableInfo() { - return (method.getLocalVariableTableEntry().getVariable(getThisPC() + getLength(), getLocalVariableTableIndex())); - } - } - - public static abstract class LocalVariableConstIndexLoad extends LocalVariableConstIndexAccessor{ - public LocalVariableConstIndexLoad(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide, - int index) { - super(methodPoolEntry, byteCode, byteReader, _wide, index); - } - - @Override public String getDescription() { - return ("push reference from local var index " + index); - } - } - - public static abstract class LocalVariableConstIndexStore extends LocalVariableConstIndexAccessor implements - AssignToLocalVariable{ - public LocalVariableConstIndexStore(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide, - int index) { - super(methodPoolEntry, byteCode, byteReader, _wide, index); - } - - @Override public boolean isDeclaration() { - LocalVariableInfo lvi = method.getLocalVariableTableEntry().getVariable(getThisPC() + getLength(), - getLocalVariableTableIndex()); - return (lvi.getStart() == getThisPC() + getLength()); - } - - @Override public String getDescription() { - return ("pop reference into local var index " + index); - } - } - - public static abstract class LocalVariableIndex08Accessor extends Index08 implements AccessLocalVariable{ - public LocalVariableIndex08Accessor(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide) { - super(methodPoolEntry, byteCode, byteReader, _wide); - } - - @Override public int getLocalVariableTableIndex() { - return (index); - } - - @Override public LocalVariableInfo getLocalVariableInfo() { - return (method.getLocalVariableTableEntry().getVariable(getThisPC() + getLength(), getLocalVariableTableIndex())); - } - } - - public static abstract class LocalVariableIndex08Load extends LocalVariableIndex08Accessor{ - public LocalVariableIndex08Load(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide) { - super(methodPoolEntry, byteCode, byteReader, _wide); - } - - @Override public String getDescription() { - return ("push reference from local var index " + index); - } - } - - public static abstract class LocalVariableIndex08Store extends LocalVariableIndex08Accessor implements AssignToLocalVariable{ - public LocalVariableIndex08Store(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide) { - super(methodPoolEntry, byteCode, byteReader, _wide); - } - - @Override public boolean isDeclaration() { - final LocalVariableTableEntry localVariableTableEntry = method.getLocalVariableTableEntry(); - final LocalVariableInfo localVarInfo = localVariableTableEntry.getVariable(getThisPC() + getLength(), - getLocalVariableTableIndex()); - return ((localVarInfo != null) && (localVarInfo.getStart() == (getThisPC() + getLength()))); - } - - @Override public String getDescription() { - return ("pop reference into local var index " + index); - } - } - - public static class I_ALOAD extends LocalVariableIndex08Load{ - public I_ALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ALOAD, _byteReader, _wide); - } - } - - public static class I_ALOAD_0 extends LocalVariableConstIndexLoad{ - public I_ALOAD_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ALOAD_0, _byteReader, _wide, 0); - } - } - - public static class I_ALOAD_1 extends LocalVariableConstIndexLoad{ - public I_ALOAD_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ALOAD_1, _byteReader, _wide, 1); - } - } - - public static class I_ALOAD_2 extends LocalVariableConstIndexLoad{ - public I_ALOAD_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ALOAD_2, _byteReader, _wide, 2); - } - } - - public static class I_ALOAD_3 extends LocalVariableConstIndexLoad{ - public I_ALOAD_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ALOAD_3, _byteReader, _wide, 3); - } - } - - public static class I_ANEWARRAY extends Index16 implements New{ - public I_ANEWARRAY(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ANEWARRAY, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("new array of reference"); - } - } - - public static class I_ARETURN extends Return{ - public I_ARETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ARETURN, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("return popped reference"); - } - } - - public static class I_ARRAYLENGTH extends Instruction{ - public I_ARRAYLENGTH(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ARRAYLENGTH, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop array push length"); - } - } - - public static class I_ASTORE extends LocalVariableIndex08Store{ - public I_ASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ASTORE, _byteReader, _wide); - } - } - - public static class I_ASTORE_0 extends LocalVariableConstIndexStore{ - public I_ASTORE_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ASTORE_0, _byteReader, _wide, 0); - } - } - - public static class I_ASTORE_1 extends LocalVariableConstIndexStore{ - public I_ASTORE_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ASTORE_1, _byteReader, _wide, 1); - } - } - - public static class I_ASTORE_2 extends LocalVariableConstIndexStore{ - public I_ASTORE_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ASTORE_2, _byteReader, _wide, 2); - } - } - - public static class I_ASTORE_3 extends LocalVariableConstIndexStore{ - public I_ASTORE_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ASTORE_3, _byteReader, _wide, 3); - } - } - - public static class I_ATHROW extends Instruction{ - public I_ATHROW(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ATHROW, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop reference and throw"); - } - } - - public static class I_BALOAD extends AccessArrayElement{ - public I_BALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.BALOAD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push byte/boolean from arrayref and index"); - } - } - - public static class I_BASTORE extends AssignToArrayElement{ - public I_BASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.BASTORE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop boolean/byte into arrayref[index]"); - } - } - - public static class I_BIPUSH extends ImmediateConstant<Integer>{ - public I_BIPUSH(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.BIPUSH, _byteReader, _wide); - value = _byteReader.u1(); - } - - @Override public String getDescription() { - return ("push (byte)"); - } - - @Override public Integer getValue() { - int byteValue = super.getValue(); - if (byteValue > 127) { - byteValue = -(256 - byteValue); - } - return (byteValue); - } - } - - public static class I_CALOAD extends AccessArrayElement{ - public I_CALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.CALOAD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push char from arrayref and index"); - } - } - - public static class I_CASTORE extends AssignToArrayElement{ - public I_CASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.CASTORE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop char into arrayref[index]"); - } - } - - public static class I_CHECKCAST extends Index16{ - public I_CHECKCAST(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.CHECKCAST, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("peek reference check against the constant accessed 16 bit"); - } - } - - public static class I_D2F extends CastOperator{ - public I_D2F(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.D2F, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop double push float"); - } - } - - public static class I_D2I extends CastOperator{ - public I_D2I(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.D2I, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop double push int"); - } - } - - public static class I_D2L extends CastOperator{ - public I_D2L(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.D2L, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop double push long"); - } - } - - public static class I_DADD extends BinaryOperator{ - public I_DADD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DADD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("add top two doubles"); - } - } - - public static class I_DALOAD extends AccessArrayElement{ - public I_DALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DALOAD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push double from arrayref and index"); - } - } - - public static class I_DASTORE extends AssignToArrayElement{ - public I_DASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DASTORE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop double into arrayref[index]"); - } - } - - public static class I_DCMPG extends Instruction{ - public I_DCMPG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DCMPG, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push result of double comparison"); - } - } - - public static class I_DCMPL extends Instruction{ - public I_DCMPL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DCMPL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push result of double comparison"); - } - } - - public static abstract class BytecodeEncodedConstant<T> extends Instruction implements Constant<T>{ - private final T value; - - public BytecodeEncodedConstant(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide, - T _value) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - value = _value; - } - - @Override public T getValue() { - return (value); - } - } - - public static abstract class ImmediateConstant<T> extends Instruction implements Constant<T>{ - protected T value; - - public ImmediateConstant(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - - @Override public T getValue() { - return (value); - } - } - - public static class I_DCONST_0 extends BytecodeEncodedConstant<Double>{ - public I_DCONST_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DCONST_0, _byteReader, _wide, 0.0); - } - - @Override public String getDescription() { - return ("push (double) 0.0"); - } - } - - public static class I_DCONST_1 extends BytecodeEncodedConstant<Double>{ - public I_DCONST_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DCONST_1, _byteReader, _wide, 1.0); - } - - @Override public String getDescription() { - return ("push (double) 1.0"); - } - } - - public static class I_DDIV extends BinaryOperator{ - public I_DDIV(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DDIV, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("div top two doubles"); - } - } - - public static class I_DLOAD extends LocalVariableIndex08Load{ - public I_DLOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DLOAD, _byteReader, _wide); - } - } - - public static class I_DLOAD_0 extends LocalVariableConstIndexLoad{ - public I_DLOAD_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DLOAD_0, _byteReader, _wide, 0); - } - } - - public static class I_DLOAD_1 extends LocalVariableConstIndexLoad{ - public I_DLOAD_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DLOAD_1, _byteReader, _wide, 1); - } - } - - public static class I_DLOAD_2 extends LocalVariableConstIndexLoad{ - public I_DLOAD_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DLOAD_2, _byteReader, _wide, 2); - } - } - - public static class I_DLOAD_3 extends LocalVariableConstIndexLoad{ - public I_DLOAD_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DLOAD_3, _byteReader, _wide, 3); - } - } - - public static class I_DMUL extends BinaryOperator{ - public I_DMUL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DMUL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("mul top two doubles"); - } - } - - public static class I_DNEG extends UnaryOperator{ - public I_DNEG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DNEG, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("neg top double"); - } - } - - public static class I_DREM extends BinaryOperator{ - public I_DREM(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DREM, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("rem top two doubles"); - } - } - - public static class I_DRETURN extends Return{ - public I_DRETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DRETURN, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("return popped double"); - } - } - - public static class I_DSTORE extends LocalVariableIndex08Store{ - public I_DSTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DSTORE, _byteReader, _wide); - } - } - - public static class I_DSTORE_0 extends LocalVariableConstIndexStore{ - public I_DSTORE_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DSTORE_0, _byteReader, _wide, 0); - } - } - - public static class I_DSTORE_1 extends LocalVariableConstIndexStore{ - public I_DSTORE_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DSTORE_1, _byteReader, _wide, 1); - } - } - - public static class I_DSTORE_2 extends LocalVariableConstIndexStore{ - public I_DSTORE_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DSTORE_2, _byteReader, _wide, 2); - } - } - - public static class I_DSTORE_3 extends LocalVariableConstIndexStore{ - public I_DSTORE_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DSTORE_3, _byteReader, _wide, 3); - } - } - - public static class I_DSUB extends BinaryOperator{ - public I_DSUB(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DSUB, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("sub top two doubles"); - } - } - - public static abstract class DUP extends Instruction{ - public DUP(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - } - - public static class I_DUP extends DUP{ - public I_DUP(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DUP, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("dup top item"); - } - } - - public static class I_DUP_X1 extends DUP{ - public I_DUP_X1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DUP_X1, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("dup top item 2 items down"); - } - } - - public static class I_DUP_X2 extends DUP{ - public I_DUP_X2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DUP_X2, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("dup top item 3 items down"); - } - } - - public static class I_DUP2 extends DUP{ - public I_DUP2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DUP2, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("dup top 2 items"); - } - } - - public static class I_DUP2_X1 extends DUP{ - public I_DUP2_X1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DUP2_X1, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("dup top 2 items 2 items down"); - } - } - - public static class I_DUP2_X2 extends DUP{ - public I_DUP2_X2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.DUP_X2, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("dup top 2 items 3 items down"); - } - } - - public static class I_F2D extends CastOperator{ - public I_F2D(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.F2D, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop float push double"); - } - } - - public static class I_F2I extends CastOperator{ - public I_F2I(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.F2I, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop float push int"); - } - } - - public static class I_F2L extends CastOperator{ - public I_F2L(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.F2L, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop float push long"); - } - } - - public static class I_FADD extends BinaryOperator{ - public I_FADD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FADD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("add top two floats"); - } - } - - public static class I_FALOAD extends AccessArrayElement{ - public I_FALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FALOAD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push float from arrayref and index"); - } - } - - public static class I_FASTORE extends AssignToArrayElement{ - public I_FASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FASTORE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop float into arrayref[index]"); - } - } - - public static class I_FCMPG extends BinaryOperator{ - public I_FCMPG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FCMPG, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push result of float comparison"); - } - } - - public static class I_FCMPL extends BinaryOperator{ - public I_FCMPL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FCMPL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push result of float comparison"); - } - } - - public static class I_FCONST_0 extends BytecodeEncodedConstant<Float>{ - public I_FCONST_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FCONST_0, _byteReader, _wide, 0f); - } - - @Override public String getDescription() { - return ("push (float) 0.0"); - } - } - - public static class I_FCONST_1 extends BytecodeEncodedConstant<Float>{ - public I_FCONST_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FCONST_1, _byteReader, _wide, 1f); - } - - @Override public String getDescription() { - return ("push (float) 1.0"); - } - } - - public static class I_FCONST_2 extends BytecodeEncodedConstant<Float>{ - public I_FCONST_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FCONST_2, _byteReader, _wide, 2f); - } - - @Override public String getDescription() { - return ("push (float) 2.0"); - } - } - - public static class I_FDIV extends BinaryOperator{ - public I_FDIV(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FDIV, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("div top two floats"); - } - } - - public static class I_FLOAD extends LocalVariableIndex08Load{ - public I_FLOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FLOAD, _byteReader, _wide); - } - } - - public static class I_FLOAD_0 extends LocalVariableConstIndexLoad{ - public I_FLOAD_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FLOAD_0, _byteReader, _wide, 0); - } - } - - public static class I_FLOAD_1 extends LocalVariableConstIndexLoad{ - public I_FLOAD_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FLOAD_1, _byteReader, _wide, 1); - } - } - - public static class I_FLOAD_2 extends LocalVariableConstIndexLoad{ - public I_FLOAD_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FLOAD_2, _byteReader, _wide, 2); - } - } - - public static class I_FLOAD_3 extends LocalVariableConstIndexLoad{ - public I_FLOAD_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FLOAD_3, _byteReader, _wide, 3); - } - } - - public static class I_FMUL extends BinaryOperator{ - public I_FMUL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FMUL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("mul top two floats"); - } - } - - public static class I_FNEG extends UnaryOperator{ - public I_FNEG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FNEG, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("neg top float"); - } - } - - public static class I_FREM extends BinaryOperator{ - public I_FREM(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FREM, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("rem top two floats"); - } - } - - public static class I_FRETURN extends Return{ - public I_FRETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FRETURN, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("return popped float"); - } - } - - public static class I_FSTORE extends LocalVariableIndex08Store{ - public I_FSTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FSTORE, _byteReader, _wide); - } - } - - public static class I_FSTORE_0 extends LocalVariableConstIndexStore{ - public I_FSTORE_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FSTORE_0, _byteReader, _wide, 0); - } - } - - public static class I_FSTORE_1 extends LocalVariableConstIndexStore{ - public I_FSTORE_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FSTORE_1, _byteReader, _wide, 1); - } - } - - public static class I_FSTORE_2 extends LocalVariableConstIndexStore{ - I_FSTORE_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FSTORE_2, _byteReader, _wide, 2); - } - } - - public static class I_FSTORE_3 extends LocalVariableConstIndexStore{ - public I_FSTORE_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FSTORE_3, _byteReader, _wide, 3); - } - } - - public static class I_FSUB extends BinaryOperator{ - public I_FSUB(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.FSUB, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("sub top two floats"); - } - } - - public static class I_GETFIELD extends Index16 implements AccessInstanceField{ - - public I_GETFIELD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.GETFIELD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push value from field referenced by 16 bit constant index"); - } - - @Override public int getConstantPoolFieldIndex() { - return (index); - } - - @Override public FieldEntry getConstantPoolFieldEntry() { - return (method.getConstantPool().getFieldEntry(getConstantPoolFieldIndex())); - } - - @Override public Instruction getInstance() { - return (getFirstChild()); - } - - @Override public int getStackConsumeCount() { - return (1); - } - - @Override public int getStackProduceCount() { - return (1); - } - } - - public static class I_GETSTATIC extends Index16 implements AccessField{ - public I_GETSTATIC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.GETSTATIC, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push static field value at 16 bit constant index"); - } - - @Override public int getConstantPoolFieldIndex() { - return (index); - } - - @Override public FieldEntry getConstantPoolFieldEntry() { - return (method.getConstantPool().getFieldEntry(getConstantPoolFieldIndex())); - } - - @Override public int getStackConsumeCount() { - return (0); - } - - @Override public int getStackProduceCount() { - return (1); - } - } - - public static class I_GOTO extends UnconditionalBranch16{ - public I_GOTO(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.GOTO, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch "); - } - } - - public static class I_GOTO_W extends Branch32{ - public I_GOTO_W(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.GOTO_W, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("goto wide branch"); - } - } - - public static class I_I2B extends CastOperator{ - public I_I2B(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.I2B, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop int push byte"); - } - } - - public static class I_I2C extends CastOperator{ - public I_I2C(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.I2C, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop int push char"); - } - } - - public static class I_I2D extends CastOperator{ - public I_I2D(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.I2D, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop int push double"); - } - } - - public static class I_I2F extends CastOperator{ - public I_I2F(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.I2F, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop int push float"); - } - } - - public static class I_I2L extends CastOperator{ - public I_I2L(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.I2L, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop int push long"); - } - } - - public static class I_I2S extends CastOperator{ - public I_I2S(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.I2S, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop int push short"); - } - } - - public static class I_IADD extends BinaryOperator{ - public I_IADD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IADD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("add top two ints"); - } - } - - public static class I_IALOAD extends AccessArrayElement{ - public I_IALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IALOAD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push int from arrayref and index"); - } - } - - public static class I_IAND extends BinaryOperator{ - public I_IAND(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IAND, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("and top two ints"); - } - } - - public static class I_IASTORE extends AssignToArrayElement{ - public I_IASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IASTORE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop int into arrayref[index]"); - } - } - - public static class I_ICONST_0 extends BytecodeEncodedConstant<Integer>{ - public I_ICONST_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ICONST_0, _byteReader, _wide, 0); - } - - @Override public String getDescription() { - return ("push (int) 0"); - } - } - - public static class I_ICONST_1 extends BytecodeEncodedConstant<Integer>{ - public I_ICONST_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ICONST_1, _byteReader, _wide, 1); - } - - @Override public String getDescription() { - return ("push (int) 1"); - } - } - - public static class I_ICONST_2 extends BytecodeEncodedConstant<Integer>{ - public I_ICONST_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ICONST_2, _byteReader, _wide, 2); - } - - @Override public String getDescription() { - return ("push (int) 2"); - } - } - - public static class I_ICONST_3 extends BytecodeEncodedConstant<Integer>{ - public I_ICONST_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ICONST_3, _byteReader, _wide, 3); - } - - @Override public String getDescription() { - return ("push (int) 3"); - } - } - - public static class I_ICONST_4 extends BytecodeEncodedConstant<Integer>{ - public I_ICONST_4(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ICONST_4, _byteReader, _wide, 4); - } - - @Override public String getDescription() { - return ("push (int) 4"); - } - } - - public static class I_ICONST_5 extends BytecodeEncodedConstant<Integer>{ - public I_ICONST_5(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ICONST_5, _byteReader, _wide, 5); - } - - @Override public String getDescription() { - return ("push (int) 5"); - } - } - - public static class I_ICONST_M1 extends BytecodeEncodedConstant<Integer>{ - public I_ICONST_M1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ICONST_M1, _byteReader, _wide, -1); - } - - @Override public String getDescription() { - return ("push (int)-1"); - } - } - - public static class I_IDIV extends BinaryOperator{ - public I_IDIV(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IDIV, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("div top two ints"); - } - } - - public static class I_IF_ACMPEQ extends If{ - public I_IF_ACMPEQ(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IF_ACMPEQ, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top references =="); - } - } - - public static class I_IF_ACMPNE extends If{ - public I_IF_ACMPNE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IF_ACMPNE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top references !="); - } - } - - public static class I_IF_ICMPEQ extends If{ - public I_IF_ICMPEQ(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IF_ICMPEQ, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top ints =="); - } - } - - public static class I_IF_ICMPGE extends If{ - public I_IF_ICMPGE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IF_ICMPGE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top ints >="); - } - } - - public static class I_IF_ICMPGT extends If{ - public I_IF_ICMPGT(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IF_ICMPGT, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top ints > "); - } - } - - public static class I_IF_ICMPLE extends If{ - public I_IF_ICMPLE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IF_ICMPLE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top ints <="); - } - } - - public static class I_IF_ICMPLT extends If{ - public I_IF_ICMPLT(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IF_ICMPLT, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top ints < "); - } - } - - public static class I_IF_ICMPNE extends If{ - public I_IF_ICMPNE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IF_ICMPNE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top ints !="); - } - } - - public static class I_IFEQ extends IfUnary{ - public I_IFEQ(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IFEQ, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top int == 0"); - } - } - - public static class I_IFGE extends IfUnary{ - public I_IFGE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IFGE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top int >= 0"); - } - } - - public static class I_IFGT extends IfUnary{ - public I_IFGT(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IFGT, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top int > 0"); - } - } - - public static class I_IFLE extends IfUnary{ - public I_IFLE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IFLE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top int <= 0"); - } - } - - public static class I_IFLT extends IfUnary{ - public I_IFLT(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IFLT, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top int < 0"); - } - } - - public static class I_IFNE extends IfUnary{ - public I_IFNE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IFNE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if stack top int != 0"); - } - } - - public static class I_IFNONNULL extends ConditionalBranch16{ - public I_IFNONNULL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IFNONNULL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if non null"); - } - } - - public static class I_IFNULL extends ConditionalBranch16{ - public I_IFNULL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IFNULL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("branch if null"); - } - } - - public static class I_IINC extends Index08{ - private int delta; - - private final boolean wide; - - public I_IINC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IINC, _byteReader, _wide); - wide = _wide; - if (wide) { - delta = _byteReader.u2(); - } else { - delta = _byteReader.u1(); - } - - } - - @Override public String getDescription() { - return ("inc var index 08 bit by byte"); - } - - public LocalVariableInfo getLocalVariableInfo() { - return (method.getLocalVariableTableEntry().getVariable(getThisPC(), getLocalVariableTableIndex())); - } - - public int getLocalVariableTableIndex() { - return (index); - } - - public int getDelta() { - return (delta); - } - - public boolean isInc() { - return getAdjust() > 0; - } - - public int getAdjust() { - int adjust = delta; - if (wide) { - if (adjust > 0x7fff) { - adjust = -0x10000 + adjust; - } - } else { - if (adjust > 0x7f) { - adjust = -0x100 + adjust; - } - } - return (adjust); - } - } - - public static class I_ILOAD extends LocalVariableIndex08Load{ - public I_ILOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ILOAD, _byteReader, _wide); - } - } - - public static class I_ILOAD_0 extends LocalVariableConstIndexLoad{ - public I_ILOAD_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ILOAD_0, _byteReader, _wide, 0); - } - } - - public static class I_ILOAD_1 extends LocalVariableConstIndexLoad{ - public I_ILOAD_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ILOAD_1, _byteReader, _wide, 1); - } - } - - public static class I_ILOAD_2 extends LocalVariableConstIndexLoad{ - public I_ILOAD_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ILOAD_2, _byteReader, _wide, 2); - } - } - - public static class I_ILOAD_3 extends LocalVariableConstIndexLoad{ - public I_ILOAD_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ILOAD_3, _byteReader, _wide, 3); - } - } - - public static class I_IMUL extends BinaryOperator{ - public I_IMUL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IMUL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("mul top two ints"); - } - } - - public static class I_INEG extends UnaryOperator{ - public I_INEG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.INEG, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("neg top int"); - } - } - - public static class I_INSTANCEOF extends Index16{ - public I_INSTANCEOF(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.INSTANCEOF, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop reference check against the constant accessed 16 bit push 1 if same"); - } - } - - public static class I_INVOKEINTERFACE extends Index16 implements InterfaceConstantPoolMethodIndexAccessor{ - private final int args; - - public I_INVOKEINTERFACE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.INVOKEINTERFACE, _byteReader, _wide); - args = _byteReader.u1(); - @SuppressWarnings("unused") final int zeroByte = _byteReader.u1(); - - } - - @Override public int getArgs() { - return (args); - } - - @Override public String getDescription() { - return ("pop args and call the interface method referenced by 16 bit constant index"); - } - - @Override public int getConstantPoolInterfaceMethodIndex() { - return (index); - } - - @Override public ConstantPool.InterfaceMethodEntry getConstantPoolInterfaceMethodEntry() { - return (method.getConstantPool().getInterfaceMethodEntry(getConstantPoolInterfaceMethodIndex())); - } - - @Override public Instruction getArg(int _arg) { - Instruction child = getFirstChild(); - _arg++; - - while (_arg-- != 0) { - child = child.getNextExpr(); - } - - return (child); - } - - @Override public Instruction getInstanceReference() { - return (getFirstChild()); - } - - @Override public int getStackConsumeCount() { - return (getConstantPoolInterfaceMethodEntry().getStackConsumeCount() + 1); // + 1 to account for instance 'this' - - } - - @Override public int getStackProduceCount() { - return (getConstantPoolInterfaceMethodEntry().getStackProduceCount()); // + 1 to account for instance 'this' - } - } - - public static class I_INVOKEDYNAMIC extends Index16 implements InterfaceConstantPoolMethodIndexAccessor{ - private final int args; - - public I_INVOKEDYNAMIC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.INVOKEDYNAMIC, _byteReader, _wide); - args = _byteReader.u1(); - @SuppressWarnings("unused") final int zeroByte = _byteReader.u1(); - - } - - @Override public int getArgs() { - return (args); - } - - @Override public String getDescription() { - return ("pop args and call the invoke dynamic method referenced by 16 bit constant index"); - } - - @Override public int getConstantPoolInterfaceMethodIndex() { - return (index); - } - - @Override public ConstantPool.InterfaceMethodEntry getConstantPoolInterfaceMethodEntry() { - return (method.getConstantPool().getInterfaceMethodEntry(getConstantPoolInterfaceMethodIndex())); - } - - @Override public Instruction getArg(int _arg) { - Instruction child = getFirstChild(); - _arg++; - while (_arg-- != 0) { - child = child.getNextExpr(); - } - return (child); - } - - @Override public Instruction getInstanceReference() { - return (getFirstChild()); - } - - @Override public int getStackConsumeCount() { - return (getConstantPoolInterfaceMethodEntry().getStackConsumeCount() + 1); // + 1 to account for instance 'this' - - } - - @Override public int getStackProduceCount() { - return (getConstantPoolInterfaceMethodEntry().getStackProduceCount()); // + 1 to account for instance 'this' - } - } - - public static class I_INVOKESPECIAL extends Index16 implements VirtualMethodCall{ - - public I_INVOKESPECIAL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.INVOKESPECIAL, _byteReader, _wide); - - } - - @Override public String getDescription() { - return ("pop object reference and args and call the special method referenced by 16 bit constant index"); - } - - @Override public int getConstantPoolMethodIndex() { - return (index); - } - - @Override public ConstantPool.MethodEntry getConstantPoolMethodEntry() { - return (method.getConstantPool().getMethodEntry(getConstantPoolMethodIndex())); - } - - @Override public Instruction getArg(int _arg) { - Instruction child = getFirstChild(); - _arg++; - while (_arg-- != 0) { - child = child.getNextExpr(); - } - return (child); - } - - @Override public Instruction getInstanceReference() { - return (getFirstChild()); - } - - @Override public int getStackConsumeCount() { - return (getConstantPoolMethodEntry().getStackConsumeCount() + 1); // + 1 to account for instance 'this' - - } - - @Override public int getStackProduceCount() { - return (getConstantPoolMethodEntry().getStackProduceCount()); - } - } - - public static class I_INVOKESTATIC extends Index16 implements MethodCall{ - - public I_INVOKESTATIC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.INVOKESTATIC, _byteReader, _wide); - - } - - @Override public String getDescription() { - return ("pop args and call the static method referenced by 16 bit constant index"); - } - - @Override public int getConstantPoolMethodIndex() { - return (index); - } - - @Override public ConstantPool.MethodEntry getConstantPoolMethodEntry() { - return (method.getConstantPool().getMethodEntry(getConstantPoolMethodIndex())); - } - - @Override public Instruction getArg(int _arg) { - Instruction child = getFirstChild(); - - while (_arg-- != 0) { - child = child.getNextExpr(); - } - - return (child); - } - - @Override public int getStackConsumeCount() { - return (getConstantPoolMethodEntry().getStackConsumeCount()); - } - - @Override public int getStackProduceCount() { - return (getConstantPoolMethodEntry().getStackProduceCount()); - } - } - - public static class I_INVOKEVIRTUAL extends Index16 implements VirtualMethodCall{ - - public I_INVOKEVIRTUAL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.INVOKEVIRTUAL, _byteReader, _wide); - - } - - @Override public String getDescription() { - return ("pop object reference and args and call the method referenced by 16 bit constant index"); - } - - @Override public int getConstantPoolMethodIndex() { - return (index); - } - - @Override public ConstantPool.MethodEntry getConstantPoolMethodEntry() { - return (method.getConstantPool().getMethodEntry(getConstantPoolMethodIndex())); - } - - @Override public Instruction getArg(int _arg) { - Instruction child = getFirstChild(); - _arg++; - - while (_arg-- != 0) { - child = child.getNextExpr(); - } - - return (child); - } - - @Override public Instruction getInstanceReference() { - return (getFirstChild()); - } - - @Override public int getStackConsumeCount() { - return (getConstantPoolMethodEntry().getStackConsumeCount() + 1); // + 1 to account for instance 'this' - } - - @Override public int getStackProduceCount() { - return (getConstantPoolMethodEntry().getStackProduceCount()); - } - } - - public static class I_IOR extends BinaryOperator{ - public I_IOR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IOR, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("or top two ints"); - } - } - - public static class I_IREM extends BinaryOperator{ - public I_IREM(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IREM, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("rem top two ints"); - } - } - - public static class I_IRETURN extends Return{ - public I_IRETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IRETURN, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("return popped int"); - } - } - - public static class I_ISHL extends BinaryOperator{ - public I_ISHL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ISHL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("shift left top int"); - } - } - - public static class I_ISHR extends BinaryOperator{ - public I_ISHR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ISHR, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("shift right top int"); - } - } - - public static class I_ISTORE extends LocalVariableIndex08Store{ - public I_ISTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ISTORE, _byteReader, _wide); - } - } - - public static class I_ISTORE_0 extends LocalVariableConstIndexStore{ - public I_ISTORE_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ISTORE_0, _byteReader, _wide, 0); - } - } - - public static class I_ISTORE_1 extends LocalVariableConstIndexStore{ - public I_ISTORE_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ISTORE_1, _byteReader, _wide, 1); - } - } - - public static class I_ISTORE_2 extends LocalVariableConstIndexStore{ - public I_ISTORE_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ISTORE_2, _byteReader, _wide, 2); - } - } - - public static class I_ISTORE_3 extends LocalVariableConstIndexStore{ - public I_ISTORE_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ISTORE_3, _byteReader, _wide, 3); - } - } - - public static class I_ISUB extends BinaryOperator{ - public I_ISUB(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.ISUB, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("sub top two ints"); - } - } - - public static class I_IUSHR extends BinaryOperator{ - public I_IUSHR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IUSHR, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("shift right top int unsigned"); - } - } - - public static class I_IXOR extends BinaryOperator{ - public I_IXOR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.IXOR, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("xor top two ints"); - } - } - - public static class I_JSR extends UnconditionalBranch16{ - public I_JSR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.JSR, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("jump to subroutine "); - } - } - - public static class I_JSR_W extends Branch32{ - public I_JSR_W(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.JSR_W, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("subroutine"); - } - } - - public static class I_L2D extends CastOperator{ - public I_L2D(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.L2D, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop long push double"); - } - } - - public static class I_L2F extends CastOperator{ - public I_L2F(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.L2F, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop long push float"); - } - } - - public static class I_L2I extends CastOperator{ - public I_L2I(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.L2I, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop long push int"); - } - } - - public static class I_LADD extends BinaryOperator{ - public I_LADD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LADD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("add top two longs"); - } - } - - public static class I_LALOAD extends AccessArrayElement{ - public I_LALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LALOAD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push long from arrayref and index"); - } - } - - public static class I_LAND extends BinaryOperator{ - public I_LAND(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LAND, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("and top two longs"); - } - } - - public static class I_LASTORE extends AssignToArrayElement{ - public I_LASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LASTORE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop long into arrayref[index]"); - } - } - - public static class I_LCMP extends BinaryOperator{ - public I_LCMP(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LCMP, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push result of long comparison"); - } - } - - public static class I_LCONST_0 extends BytecodeEncodedConstant<Long>{ - public I_LCONST_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LCONST_0, _byteReader, _wide, 0L); - } - - @Override public String getDescription() { - return ("push (long) 0"); - } - } - - public static class I_LCONST_1 extends BytecodeEncodedConstant<Long>{ - public I_LCONST_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LCONST_1, _byteReader, _wide, 1L); - } - - @Override public String getDescription() { - return ("push (long) 1"); - } - } - - public static class I_LDC extends Index08 implements ConstantPoolEntryConstant{ - public I_LDC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LDC, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push constant at 08 bit index"); - } - - @Override public Object getValue() { - return (method.getConstantPool().getConstantEntry(getConstantPoolIndex())); - - } - - @Override public int getConstantPoolIndex() { - return (index); - } - - @Override public Entry getConstantPoolEntry() { - return (method.getConstantPool().get(getConstantPoolIndex())); - } - } - - public static class I_LDC_W extends Index16 implements ConstantPoolEntryConstant{ - public I_LDC_W(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LDC_W, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push constant at 16 bit index"); - } - - @Override public int getConstantPoolIndex() { - return (index); - } - - @Override public Object getValue() { - return (method.getConstantPool().getConstantEntry(getConstantPoolIndex())); - - } - - @Override public Entry getConstantPoolEntry() { - return (method.getConstantPool().get(getConstantPoolIndex())); - } - } - - public static class I_LDC2_W extends Index16 implements ConstantPoolEntryConstant{ - public I_LDC2_W(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LDC2_W, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push long/double constant at 16 bit index"); - } - - @Override public int getConstantPoolIndex() { - return (index); - } - - @Override public Entry getConstantPoolEntry() { - return (method.getConstantPool().get(getConstantPoolIndex())); - } - - @Override public Object getValue() { - return (method.getConstantPool().getConstantEntry(getConstantPoolIndex())); - } - } - - public static class I_LDIV extends BinaryOperator{ - public I_LDIV(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LDIV, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("div top two longs"); - } - } - - public static class I_LLOAD extends LocalVariableIndex08Load{ - public I_LLOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LLOAD, _byteReader, _wide); - } - } - - public static class I_LLOAD_0 extends LocalVariableConstIndexLoad{ - public I_LLOAD_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LLOAD_0, _byteReader, _wide, 0); - } - } - - public static class I_LLOAD_1 extends LocalVariableConstIndexLoad{ - public I_LLOAD_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LLOAD_1, _byteReader, _wide, 1); - } - } - - public static class I_LLOAD_2 extends LocalVariableConstIndexLoad{ - public I_LLOAD_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LLOAD_2, _byteReader, _wide, 2); - } - } - - public static class I_LLOAD_3 extends LocalVariableConstIndexLoad{ - public I_LLOAD_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LLOAD_3, _byteReader, _wide, 3); - } - } - - public static class I_LMUL extends BinaryOperator{ - public I_LMUL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LMUL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("mul top two longs"); - } - } - - public static class I_LNEG extends UnaryOperator{ - public I_LNEG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LNEG, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("neg top long"); - } - } - - public static class I_LOOKUPSWITCH extends Switch{ - private final int[] matches; - - private final int npairs; - - public I_LOOKUPSWITCH(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LOOKUPSWITCH, _byteReader, _wide); - final int operandStart = _byteReader.getOffset(); - final int padLength = ((operandStart % 4) == 0) ? 0 : 4 - (operandStart % 4); - _byteReader.bytes(padLength); - offset = _byteReader.u4(); - npairs = _byteReader.u4(); - offsets = new int[npairs]; - matches = new int[npairs]; - for (int i = 0; i < npairs; i++) { - matches[i] = _byteReader.u4(); - offsets[i] = _byteReader.u4(); - } - } - - @Override public String getDescription() { - return ("help!"); - } - - public int[] getMatches() { - return (matches); - } - - public int getNpairs() { - return (npairs); - } - } - - public static class I_LOR extends BinaryOperator{ - public I_LOR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LOR, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("or top two longs"); - } - } - - public static class I_LREM extends BinaryOperator{ - public I_LREM(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LREM, _byteReader, _wide); - - } - - @Override public String getDescription() { - return ("rem top two longs"); - } - } - - public static class I_LRETURN extends Return{ - public I_LRETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LRETURN, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("return popped long"); - } - } - - public static class I_LSHL extends BinaryOperator{ - public I_LSHL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LSHL, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("shift left top long"); - } - } - - public static class I_LSHR extends BinaryOperator{ - public I_LSHR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LSHR, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("shift right top long"); - } - } - - public static class I_LSTORE extends LocalVariableIndex08Store{ - public I_LSTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LSTORE, _byteReader, _wide); - } - } - - public static class I_LSTORE_0 extends LocalVariableConstIndexStore{ - public I_LSTORE_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LSTORE_0, _byteReader, _wide, 0); - } - } - - public static class I_LSTORE_1 extends LocalVariableConstIndexStore{ - public I_LSTORE_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LSTORE_1, _byteReader, _wide, 1); - } - } - - public static class I_LSTORE_2 extends LocalVariableConstIndexStore{ - public I_LSTORE_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LSTORE_2, _byteReader, _wide, 2); - } - } - - public static class I_LSTORE_3 extends LocalVariableConstIndexStore{ - public I_LSTORE_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LSTORE_3, _byteReader, _wide, 3); - } - } - - public static class I_LSUB extends BinaryOperator{ - public I_LSUB(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LSUB, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("sub top two longs"); - } - } - - public static class I_LUSHR extends BinaryOperator{ - public I_LUSHR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LUSHR, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("shift right top long unsigned"); - } - } - - public static class I_LXOR extends BinaryOperator{ - public I_LXOR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.LXOR, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("xor top two longs"); - } - } - - public static class I_MONITORENTER extends Instruction{ - public I_MONITORENTER(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.MONITORENTER, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop reference and inc monitor"); - } - } - - public static class I_MONITOREXIT extends Instruction{ - public I_MONITOREXIT(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.MONITOREXIT, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop reference and dec monitor"); - } - } - - public static class I_MULTIANEWARRAY extends Index16 implements New{ - private final int dimensions; - - public I_MULTIANEWARRAY(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.MULTIANEWARRAY, _byteReader, _wide); - dimensions = _byteReader.u1(); - } - - @Override public String getDescription() { - return ("create a multi dimension array of refernce types "); - } - - public int getDimensions() { - return (dimensions); - } - } - - public static class I_NEW extends Index16 implements New{ - public I_NEW(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.NEW, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("new"); - } - } - - public static class I_NEWARRAY extends Instruction implements New{ - private final int type; - - public I_NEWARRAY(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.NEWARRAY, _byteReader, _wide); - type = _byteReader.u1(); - } - - @Override public String getDescription() { - return ("new array simple type"); - } - - public int getType() { - return (type); - } - } - - public static class I_NOP extends Instruction{ - public I_NOP(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.NOP, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("no op"); - } - } - - public static class I_POP extends Instruction{ - public I_POP(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.POP, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop one item"); - } - } - - public static class I_POP2 extends Instruction{ - public I_POP2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.POP2, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop 2 items"); - } - } - - public static class I_PUTFIELD extends Index16 implements AssignToInstanceField{ - public I_PUTFIELD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.PUTFIELD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop stack value into field referenced by 16 bit constant index"); - } - - @Override public int getConstantPoolFieldIndex() { - return (index); - } - - @Override public FieldEntry getConstantPoolFieldEntry() { - return (method.getConstantPool().getFieldEntry(getConstantPoolFieldIndex())); - } - - @Override public int getStackConsumeCount() { - return (2); - } - - @Override public int getStackProduceCount() { - return (0); - } - - @Override public Instruction getInstance() { - return (getFirstChild()); - } - - @Override public Instruction getValueToAssign() { - return (getLastChild()); - } - } - - public static class I_PUTSTATIC extends Index16 implements AssignToField{ - public I_PUTSTATIC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.PUTSTATIC, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop stack value into 16 bit constant index as field"); - } - - @Override public int getConstantPoolFieldIndex() { - return (index); - } - - @Override public FieldEntry getConstantPoolFieldEntry() { - return (method.getConstantPool().getFieldEntry(getConstantPoolFieldIndex())); - } - - @Override public int getStackConsumeCount() { - return (1); - } - - @Override public int getStackProduceCount() { - return (0); - } - - @Override public Instruction getValueToAssign() { - return (getLastChild()); - } - } - - public static class I_RET extends Index08 implements AssignToLocalVariable{ - public I_RET(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.RET, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("return to pc in local var index 08 bit"); - } - - @Override public LocalVariableInfo getLocalVariableInfo() { - return (method.getLocalVariableTableEntry().getVariable(getThisPC() + getLength(), getLocalVariableTableIndex())); - } - - @Override public boolean isDeclaration() { - return (method.getLocalVariableTableEntry().getVariable(getThisPC() + getLength(), getLocalVariableTableIndex()) - .getStart() == (getThisPC() + getLength())); - } - - @Override public int getLocalVariableTableIndex() { - return (index); - } - - // @Override Instruction getValue() { - // return (getFirstChild()); - //} - } - - public static class I_RETURN extends Return{ - public I_RETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.RETURN, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("return void"); - } - } - - public static class I_SALOAD extends AccessArrayElement{ - public I_SALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.SALOAD, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("push short from arrayref and index"); - } - } - - public static class I_SASTORE extends AssignToArrayElement{ - public I_SASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.SASTORE, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("pop short into arrayref[index]"); - } - } - - public static class I_SIPUSH extends ImmediateConstant<Integer>{ - public I_SIPUSH(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.SIPUSH, _byteReader, _wide); - value = _byteReader.u2(); - } - - @Override public String getDescription() { - return ("push (short)"); - } - } - - public static class I_SWAP extends Instruction{ - public I_SWAP(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.SWAP, _byteReader, _wide); - } - - @Override public String getDescription() { - return ("swap top 2 items"); - } - } - - public static class I_TABLESWITCH extends Switch{ - private final int high; - - private final int low; - - public I_TABLESWITCH(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.TABLESWITCH, _byteReader, _wide); - final int operandStart = _byteReader.getOffset(); - final int padLength = ((operandStart % 4) == 0) ? 0 : 4 - (operandStart % 4); - _byteReader.bytes(padLength); - offset = _byteReader.u4(); - low = _byteReader.u4(); - high = _byteReader.u4(); - offsets = new int[(high - low) + 1]; - for (int i = low; i <= high; i++) { - offsets[i - low] = _byteReader.u4(); - } - } - - @Override public String getDescription() { - return ("help!"); - } - - public int getHigh() { - return (high); - } - - public int getLow() { - return (low); - } - } - - public static class I_WIDE extends Instruction{ - private boolean iinc; - - private int increment; - - private final int index; - - private final int wideopcode; - - public I_WIDE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, ByteCode.WIDE, _byteReader, _wide); - wideopcode = _byteReader.u1(); - index = _byteReader.u2(); - if ((((wideopcode >= 0x15) && (wideopcode <= 0x19)) || ((wideopcode >= 0x36) && (wideopcode <= 0x3a)) || (wideopcode == 0xa9))) { - iinc = false; - } else { - increment = _byteReader.u2(); - iinc = true; - } - } - - @Override public String getDescription() { - return ("help"); - } - - public int getIncrement() { - return (increment); - } - - public int getIndex() { - return (index); - } - - public int getWideopcode() { - return (wideopcode); - } - - public boolean isiinc() { - return (iinc); - } - } - - public static class I_END extends Instruction{ - public I_END(MethodModel method, int _pc) { - super(method, ByteCode.NONE, _pc); - } - - @Override public String getDescription() { - return ("END"); - } - } - - public static abstract class Index extends Instruction{ - protected int index; - - public Index(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - } - - public static abstract class IndexConst extends Index{ - public IndexConst(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide, int _index) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - index = _index; - } - } - - public static abstract class Index08 extends Index{ - public Index08(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - if (_wide) { - index = _byteReader.u2(); - } else { - index = _byteReader.u1(); - } - } - } - - public static abstract class Index16 extends Index{ - public Index16(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - index = _byteReader.u2(); - } - } - - public static abstract class Return extends Instruction{ - public Return(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _byteCode, _byteReader, _wide); - } - } - - public static abstract class Switch extends Branch{ - public Switch(MethodModel _methodPoolEntry, ByteCode _code, ByteReader _byteReader, boolean _wide) { - super(_methodPoolEntry, _code, _byteReader, _wide); - } - - protected int[] offsets; - - protected Instruction[] targets; - - public Instruction getTarget(int _index) { - return (targets[_index]); - } - - public void setTarget(int _index, Instruction _instruction) { - targets[_index] = _instruction; - } - - public int getAbsolute(int _index) { - return (getThisPC() + offsets[_index]); - } - - public int getOffset(int _index) { - return (offsets[_index]); - } - - public int[] getOffsets() { - return (offsets); - } - - public int getSize() { - return (offsets.length); - } - } - - public interface MethodCall{ - int getConstantPoolMethodIndex(); - - MethodEntry getConstantPoolMethodEntry(); - - Instruction getArg(int _arg); - } - - public interface VirtualMethodCall extends MethodCall{ - Instruction getInstanceReference(); - } - - public interface InterfaceConstantPoolMethodIndexAccessor{ - public int getConstantPoolInterfaceMethodIndex(); - - public ConstantPool.InterfaceMethodEntry getConstantPoolInterfaceMethodEntry(); - - public Instruction getInstanceReference(); - - public int getArgs(); - - public Instruction getArg(int _arg); - } - - public static interface New{ - } - - public interface FieldReference{ - public int getConstantPoolFieldIndex(); - - public FieldEntry getConstantPoolFieldEntry(); - } - - public interface AccessField extends FieldReference{ - - } - - public interface AssignToField extends FieldReference{ - Instruction getValueToAssign(); - } - - public interface AccessInstanceField extends AccessField{ - Instruction getInstance(); - } - - public interface AssignToInstanceField extends AssignToField{ - Instruction getInstance(); - } - - public interface LocalVariableTableIndexAccessor{ - int getLocalVariableTableIndex(); - - LocalVariableInfo getLocalVariableInfo(); - } - - public interface AccessLocalVariable extends LocalVariableTableIndexAccessor{ - - } - - public interface AssignToLocalVariable extends LocalVariableTableIndexAccessor{ - boolean isDeclaration(); - } - - public interface Constant<T> { - T getValue(); - } - - @SuppressWarnings("unchecked") public interface ConstantPoolEntryConstant extends Constant{ - int getConstantPoolIndex(); - - ConstantPool.Entry getConstantPoolEntry(); - }; - - public interface HasOperator{ - Operator getOperator(); - } - - public interface Binary extends HasOperator{ - Instruction getLhs(); - - Instruction getRhs(); - } - - public interface Unary extends HasOperator{ - Instruction getUnary(); - } - - public static class CloneInstruction extends Instruction{ - private final Instruction cloning; - - public CloneInstruction(MethodModel method, Instruction _cloning) { - super(method, ByteCode.CLONE, -1); - cloning = _cloning; - } - - @Override public String getDescription() { - return ("CLONE! " + getByteCode()); - } - - @Override public int getStackConsumeCount() { - return (cloning.getStackConsumeCount()); - } - - @Override public int getStackProduceCount() { - return (cloning.getStackProduceCount()); - } - - @Override public Instruction getReal() { - return (cloning); - } - } - - public static class IncrementInstruction extends Instruction{ - private final Instruction fieldOrVariable; - - private final boolean isInc; - - private final boolean isPre; - - public Instruction getFieldOrVariableReference() { - return fieldOrVariable; - } - - public boolean isPre() { - return isPre; - } - - public IncrementInstruction(MethodModel method, Instruction _fieldOrVariable, boolean _isInc, boolean _isPre) { - super(method, ByteCode.INCREMENT, -1); - - fieldOrVariable = _fieldOrVariable; - isPre = _isPre; - isInc = _isInc; - } - - @Override public String getDescription() { - return ("INCREMENT Local Variable! " + getByteCode()); - } - - public boolean isInc() { - return (isInc); - } - - @Override public Instruction getStartInstruction() { - return (fieldOrVariable.getStartInstruction()); - } - } - - public static class InlineAssignInstruction extends Instruction{ - private final AssignToLocalVariable assignToLocalVariable; - - private final Instruction rhs; - - public InlineAssignInstruction(MethodModel method, AssignToLocalVariable _assignToLocalVariable, Instruction _rhs) { - super(method, ByteCode.INLINE_ASSIGN, -1); - assignToLocalVariable = _assignToLocalVariable; - rhs = _rhs; - } - - @Override public String getDescription() { - return ("INLINE ASSIGN! " + getByteCode()); - } - - public AssignToLocalVariable getAssignToLocalVariable() { - return (assignToLocalVariable); - } - - public Instruction getRhs() { - return (rhs); - } - } - - public static class FieldArrayElementAssign extends Instruction{ - private final AssignToArrayElement assignToArrayElement; - - private final Instruction rhs; - - public FieldArrayElementAssign(MethodModel method, AssignToArrayElement _assignToArrayElement, Instruction _rhs) { - super(method, ByteCode.FIELD_ARRAY_ELEMENT_ASSIGN, -1); - assignToArrayElement = _assignToArrayElement; - rhs = _rhs; - } - - @Override public String getDescription() { - return ("FIELD ARRAY ELEMENT INCREMENT! " + getByteCode()); - } - - public AssignToArrayElement getAssignToArrayElement() { - return (assignToArrayElement); - } - - public Instruction getRhs() { - return (rhs); - } - } - - public static class FieldArrayElementIncrement extends Instruction{ - private final AssignToArrayElement assignToArrayElement; - - private final boolean isPre; - - private final boolean isInc; - - public FieldArrayElementIncrement(MethodModel method, AssignToArrayElement _assignToArrayElement, boolean _isInc, - boolean _isPre) { - super(method, ByteCode.FIELD_ARRAY_ELEMENT_INCREMENT, -1); - assignToArrayElement = _assignToArrayElement; - isPre = _isPre; - isInc = _isInc; - } - - @Override public String getDescription() { - return ("FIELD ARRAY ELEMENT INCREMENT! " + getByteCode()); - } - - public AssignToArrayElement getAssignToArrayElement() { - return (assignToArrayElement); - } - - public boolean isPre() { - return (isPre); - } - - public boolean isInc() { - return (isInc); - } - } - - public static class MultiAssignInstruction extends Instruction{ - private final Instruction from, to, common; - - public MultiAssignInstruction(MethodModel method, Instruction _common, Instruction _from, Instruction _to) { - super(method, ByteCode.MULTI_ASSIGN, -1); - common = _common; - from = _from; - to = _to; - } - - @Override public String getDescription() { - return ("MULTIASSIGN! " + getByteCode()); - } - - public Instruction getTo() { - return (to); - } - - public Instruction getFrom() { - return (from); - } - - public Instruction getCommon() { - return (common); - } - } - - public static class FakeGoto extends UnconditionalBranch{ - - public FakeGoto(MethodModel _methodPoolEntry, Instruction _target) { - super(_methodPoolEntry, ByteCode.FAKEGOTO, _target); - } - - @Override public String getDescription() { - return "FAKE goto"; - } - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.instruction; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import com.aparapi.internal.model.MethodModel; +import com.aparapi.internal.model.ClassModel.ConstantPool; +import com.aparapi.internal.model.ClassModel.ConstantPool.Entry; +import com.aparapi.internal.model.ClassModel.ConstantPool.FieldEntry; +import com.aparapi.internal.model.ClassModel.ConstantPool.MethodEntry; +import com.aparapi.internal.model.ClassModel.LocalVariableTableEntry; +import com.aparapi.internal.model.ClassModel.LocalVariableInfo; +import com.aparapi.internal.reader.ByteReader; + +public class InstructionSet{ + + public static enum LoadSpec { + NONE, // + F, // Float + D, // Double + I, // Integer + L, // Long + A, // Array + O, // Object + } + + public static enum StoreSpec { + NONE, // + F, // Float + D, // Double + I, // Integer + L, // Long + A, // Array + O, // Object + } + + public static enum TypeSpec { + NONE("none", "none", 0, 0), // + Z("Z", "boolean", 4, 1), // Note 'Z' is the java code for 'boolean' type + C("C", "char", 2, 1), // + F("F", "float", 4, 1), // + D("D", "double", 8, 2), // + B("B", "byte", 1, 1), // + S("S", "short", 2, 1), // + I("I", "int", 4, 1), // + L("L", "long", 8, 1), // + J("J", "long", 8, 1), // Note J is the java code for 'long' type + A("A", "array", 4, 1), // + O("O", "object", 4, 1), + N("N", "null", 4, 1), + IorForS("IorForS", "int, float or String depending on constant pool entry", 4, 1), + LorD("LorD", "long or float depending upon the constant pool entry", 8, 2), + RA("RA", "return address", 4, 1), + UNKNOWN("UNKNOWN", "unknown", -1, -1), + ARGS("ARGS", "args to method call", -1, -1); + + private final String longName; + + private final String shortName; + + private final int size; + + private final int slots; + + private TypeSpec(String _shortName, String _longName, int _size, int _slots) { + shortName = _shortName; + longName = _longName; + size = _size; + slots = _slots; + } + + public int getSize() { + return (size); + } + + public int getSlots() { + return (slots); + } + + public String getLongName() { + return (longName); + } + + public String getShortName() { + return (shortName); + } + } + + /** + * Represents an Operator + * + * @author gfrost + * + */ + + public static enum Operator { + NONE, + LogicalOr(true, "||"), // + LogicalAnd(true, "&&", LogicalOr), // + Equal(true, "=="), // + NotEqual(true, "!=", Equal), // + LessThan(true, "<"), // + GreaterThanOrEqual(true, ">=", LessThan), // + GreaterThan(true, ">"), // + LessThanOrEqual(true, "<=", GreaterThan), // + EqualNULL(true, "NULL=="), + NotEqualNULL(true, "NULL!=", EqualNULL), // + + BitwiseOr(true, "|"), // + BitwiseAnd(true, "&"), // + BitwiseXor(true, "^"), + + LeftShift(true, "<<"), // + ArithmeticRightShift(true, ">>>"), // + LogicalRightShift(true, ">>"), // was >>> but this caused issues in opencl + + Add(true, "+"), // + Sub(true, "-"), // + + Div(true, "/"), // + Rem(true, "%"), // + Mul(true, "*"), // + + Neg(false, "-"), // + Pos(false, "+"), // + + I2FCast(false, "(float)"), + I2LCast(false, "(long)"), // + I2DCast(false, "(double)"), // + L2ICast(false, "(int)"), // + L2FCast(false, "(float)"), // + L2DCast(false, "(double)"), // + F2ICast(false, "(int)"), // + F2LCast(false, "(long)"), // + F2DCast(false, "(double)"), // + D2ICast(false, "(int)"), // + D2LCast(false, "(long)"), // + D2FCast(false, "(float)"), // + I2BCast(false, "(byte)"), // + I2CCast(false, "(char)"), // + I2SCast(false, "(short)"); + + private final String text; + + private final boolean binary; + + private Operator compliment; + + private Operator(boolean _binary, String _text) { + + text = _text; + binary = _binary; + } + + private Operator(boolean _binary, String _text, Operator _c) { + this(_binary, _text); + compliment = _c; + compliment.compliment = this; + } + + private Operator() { + this(false, null); + } + + public String getText() { + return text; + } + + public Operator getCompliment() { + return (compliment); + } + + public String getText(boolean _invert) { + return (_invert ? compliment.getText() : getText()); + } + + public boolean isBinary() { + return (binary); + + } + + public boolean isUnary() { + return (!equals(Operator.NONE) && !isBinary()); + + } + } + + public static enum PushSpec { + NONE, // + UNKNOWN, // + I(TypeSpec.I), // + II(TypeSpec.I, TypeSpec.I), // + III(TypeSpec.I, TypeSpec.I, TypeSpec.I), // + IIII(TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I), // + IIIII(TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I), // + IIIIII(TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I), // + L(TypeSpec.L), // + F(TypeSpec.F), // + D(TypeSpec.D), // + O(TypeSpec.O), // + A(TypeSpec.A), // + N(TypeSpec.N), // + IorForS(TypeSpec.IorForS), // + LorD(TypeSpec.LorD), // + RA(TypeSpec.RA); + + private PushSpec(TypeSpec... _types) { + types = _types; + } + + private final TypeSpec[] types; + + public int getStackAdjust() { + return (types.length); + } + } + + public static enum PopSpec { + NONE, // + UNKNOWN(TypeSpec.UNKNOWN), // + I(TypeSpec.I), // + II(TypeSpec.I, TypeSpec.I), // + III(TypeSpec.I, TypeSpec.I, TypeSpec.I), // + IIII(TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I), // + IIIII(TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I, TypeSpec.I), // + L(TypeSpec.L), // + LL(TypeSpec.L, TypeSpec.L), // + F(TypeSpec.F), // + FF(TypeSpec.F, TypeSpec.F), // + D(TypeSpec.D), // + DD(TypeSpec.D, TypeSpec.D), // + O(TypeSpec.O), // + OO(TypeSpec.O, TypeSpec.O), // + A(TypeSpec.A), // + AI(TypeSpec.A, TypeSpec.I), // + AII(TypeSpec.A, TypeSpec.I, TypeSpec.I), // + AIF(TypeSpec.A, TypeSpec.I, TypeSpec.F), // + AID(TypeSpec.A, TypeSpec.I, TypeSpec.D), // + AIL(TypeSpec.A, TypeSpec.I, TypeSpec.L), // + AIC(TypeSpec.A, TypeSpec.I, TypeSpec.C), // + AIS(TypeSpec.A, TypeSpec.I, TypeSpec.S), // + AIB(TypeSpec.A, TypeSpec.I, TypeSpec.B), // + AIO(TypeSpec.A, TypeSpec.I, TypeSpec.O), // + LI(TypeSpec.L, TypeSpec.I), // + OUNKNOWN(TypeSpec.O, TypeSpec.UNKNOWN), // + ARGS(TypeSpec.ARGS), // + OARGS(TypeSpec.O, TypeSpec.ARGS), // + ; + + private PopSpec(TypeSpec... _types) { + types = _types; + } + + private final TypeSpec[] types; + + public int getStackAdjust() { + return (types.length); + } + } + + public static enum ImmediateSpec { + NONE("NONE"), // + UNKNOWN("UNKNOWN"), // + Bconst("byte constant value", TypeSpec.B), // + Sconst("short constant value", TypeSpec.S), // + Bcpci("byte constant pool constant index", TypeSpec.B), // + Scpci("short constant pool constant index", TypeSpec.S), // + Icpci("int constant pool index", TypeSpec.I), // + Blvti("byte local variable table index", TypeSpec.B), + Spc("short pc", TypeSpec.S), + Ipc("int pc", TypeSpec.I), + Scpfi("short constant pool field index", TypeSpec.S), + Scpmi("short constant pool method index", TypeSpec.S), + ScpmiBB("short constant pool method index, byte count, byte (always zero)", TypeSpec.S, TypeSpec.B, TypeSpec.B), + ScpciBdim("short constant pool class index, byte dimensions", TypeSpec.S, TypeSpec.B), + BlvtiBconst("byte local variable table index, byte constant value", TypeSpec.B, TypeSpec.B); + + private final String name; + + private ImmediateSpec(String _name, TypeSpec... _types) { + + name = _name; + types = _types; + } + + private final TypeSpec[] types; + + public String getName() { + return (name); + } + + public TypeSpec[] getTypes() { + return (types); + } + } + + public static enum ByteCode { + // name, operation type, immediateOperands, pop operands, push operands + NOP(null, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, PopSpec.NONE, PushSpec.NONE, Operator.NONE), // + ACONST_NULL(I_ACONST_NULL.class, PushSpec.N), // + ICONST_M1(I_ICONST_M1.class, PushSpec.I), // + ICONST_0(I_ICONST_0.class, PushSpec.I), // + ICONST_1(I_ICONST_1.class, PushSpec.I), // + ICONST_2(I_ICONST_2.class, PushSpec.I), // + ICONST_3(I_ICONST_3.class, PushSpec.I), // + ICONST_4(I_ICONST_4.class, PushSpec.I), // + ICONST_5(I_ICONST_5.class, PushSpec.I), // + LCONST_0(I_LCONST_0.class, PushSpec.L), // + LCONST_1(I_LCONST_1.class, PushSpec.L), // + FCONST_0(I_FCONST_0.class, PushSpec.F), // + FCONST_1(I_FCONST_1.class, PushSpec.F), // + FCONST_2(I_FCONST_2.class, PushSpec.F), // + DCONST_0(I_DCONST_0.class, PushSpec.D), // + DCONST_1(I_DCONST_1.class, PushSpec.D), // + BIPUSH(I_BIPUSH.class, ImmediateSpec.Bconst, PushSpec.I), // + SIPUSH(I_SIPUSH.class, ImmediateSpec.Sconst, PushSpec.I), // + LDC(I_LDC.class, ImmediateSpec.Bcpci, PushSpec.IorForS), // + LDC_W(I_LDC_W.class, ImmediateSpec.Scpci, PushSpec.IorForS), // + LDC2_W(I_LDC2_W.class, ImmediateSpec.Scpci, PushSpec.LorD), // + ILOAD(I_ILOAD.class, LoadSpec.I, ImmediateSpec.Blvti, PushSpec.I), // + LLOAD(I_LLOAD.class, LoadSpec.L, ImmediateSpec.Blvti, PushSpec.L), // + FLOAD(I_FLOAD.class, LoadSpec.F, ImmediateSpec.Blvti, PushSpec.F), // + DLOAD(I_DLOAD.class, LoadSpec.F, ImmediateSpec.Blvti, PushSpec.D), // + ALOAD(I_ALOAD.class, LoadSpec.A, ImmediateSpec.Blvti, PushSpec.O), // + ILOAD_0(I_ILOAD_0.class, LoadSpec.I, PushSpec.I), // + ILOAD_1(I_ILOAD_1.class, LoadSpec.I, PushSpec.I), // + ILOAD_2(I_ILOAD_2.class, LoadSpec.I, PushSpec.I), // + ILOAD_3(I_ILOAD_3.class, LoadSpec.I, PushSpec.I), // + LLOAD_0(I_LLOAD_0.class, LoadSpec.L, PushSpec.L), // + LLOAD_1(I_LLOAD_1.class, LoadSpec.L, PushSpec.L), // + LLOAD_2(I_LLOAD_2.class, LoadSpec.L, PushSpec.L), // + LLOAD_3(I_LLOAD_3.class, LoadSpec.L, PushSpec.L), // + FLOAD_0(I_FLOAD_0.class, LoadSpec.F, PushSpec.F), // + FLOAD_1(I_FLOAD_1.class, LoadSpec.F, PushSpec.F), // + FLOAD_2(I_FLOAD_2.class, LoadSpec.F, PushSpec.F), // + FLOAD_3(I_FLOAD_3.class, LoadSpec.F, PushSpec.F), // + DLOAD_0(I_DLOAD_0.class, LoadSpec.D, PushSpec.D), // + DLOAD_1(I_DLOAD_1.class, LoadSpec.D, PushSpec.D), // + DLOAD_2(I_DLOAD_2.class, LoadSpec.D, PushSpec.D), // + DLOAD_3(I_DLOAD_3.class, LoadSpec.D, PushSpec.D), // + ALOAD_0(I_ALOAD_0.class, LoadSpec.A, PushSpec.O), // + ALOAD_1(I_ALOAD_1.class, LoadSpec.A, PushSpec.O), // + ALOAD_2(I_ALOAD_2.class, LoadSpec.A, PushSpec.O), // + ALOAD_3(I_ALOAD_3.class, LoadSpec.A, PushSpec.O), // + IALOAD(I_IALOAD.class, PopSpec.AI, PushSpec.I), // + LALOAD(I_LALOAD.class, PopSpec.AI, PushSpec.L), // + FALOAD(I_FALOAD.class, PopSpec.AI, PushSpec.F), // + DALOAD(I_DALOAD.class, PopSpec.AI, PushSpec.D), // + AALOAD(I_AALOAD.class, PopSpec.AI, PushSpec.A), // + BALOAD(I_BALOAD.class, PopSpec.AI, PushSpec.I), // + CALOAD(I_CALOAD.class, PopSpec.AI, PushSpec.I), // + SALOAD(I_SALOAD.class, PopSpec.AI, PushSpec.I), // + ISTORE(I_ISTORE.class, StoreSpec.I, ImmediateSpec.Blvti, PopSpec.I), // + LSTORE(I_LSTORE.class, StoreSpec.L, ImmediateSpec.Blvti, PopSpec.L), // + FSTORE(I_FSTORE.class, StoreSpec.F, ImmediateSpec.Blvti, PopSpec.F), // + DSTORE(I_DSTORE.class, StoreSpec.D, ImmediateSpec.Blvti, PopSpec.D), // + ASTORE(I_ASTORE.class, StoreSpec.A, ImmediateSpec.Blvti, PopSpec.O), // + ISTORE_0(I_ISTORE_0.class, StoreSpec.I, PopSpec.I), // + ISTORE_1(I_ISTORE_1.class, StoreSpec.I, PopSpec.I), // + ISTORE_2(I_ISTORE_2.class, StoreSpec.I, PopSpec.I), // + ISTORE_3(I_ISTORE_3.class, StoreSpec.I, PopSpec.I), // + LSTORE_0(I_LSTORE_0.class, StoreSpec.L, PopSpec.L), // + LSTORE_1(I_LSTORE_1.class, StoreSpec.L, PopSpec.L), // + LSTORE_2(I_LSTORE_2.class, StoreSpec.L, PopSpec.L), // + LSTORE_3(I_LSTORE_3.class, StoreSpec.L, PopSpec.L), // + FSTORE_0(I_FSTORE_0.class, StoreSpec.F, PopSpec.F), // + FSTORE_1(I_FSTORE_1.class, StoreSpec.F, PopSpec.F), // + FSTORE_2(I_FSTORE_2.class, StoreSpec.F, PopSpec.F), // + FSTORE_3(I_FSTORE_3.class, StoreSpec.F, PopSpec.F), // + DSTORE_0(I_DSTORE_0.class, StoreSpec.D, PopSpec.D), // + DSTORE_1(I_DSTORE_1.class, StoreSpec.D, PopSpec.D), // + DSTORE_2(I_DSTORE_2.class, StoreSpec.D, PopSpec.D), // + DSTORE_3(I_DSTORE_3.class, StoreSpec.D, PopSpec.D), // + ASTORE_0(I_ASTORE_0.class, StoreSpec.A, PopSpec.O), // + ASTORE_1(I_ASTORE_1.class, StoreSpec.A, PopSpec.O), // + ASTORE_2(I_ASTORE_2.class, StoreSpec.A, PopSpec.O), // + ASTORE_3(I_ASTORE_3.class, StoreSpec.A, PopSpec.O), // + IASTORE(I_IASTORE.class, PopSpec.AII), // + LASTORE(I_LASTORE.class, PopSpec.AIL), // + FASTORE(I_FASTORE.class, PopSpec.AIF), // + DASTORE(I_DASTORE.class, PopSpec.AID), // + AASTORE(I_AASTORE.class, PopSpec.AIO), // + BASTORE(I_BASTORE.class, PopSpec.AIB), // + CASTORE(I_CASTORE.class, PopSpec.AIC), // + SASTORE(I_SASTORE.class, PopSpec.AIS), // + POP(I_POP.class, PopSpec.I), // + POP2(I_POP2.class, PopSpec.II), // + DUP(I_DUP.class, PopSpec.I, PushSpec.II), // + DUP_X1(I_DUP_X1.class, PopSpec.II, PushSpec.III), // + DUP_X2(I_DUP_X2.class, PopSpec.III, PushSpec.IIII), // + DUP2(I_DUP2.class, PopSpec.II, PushSpec.IIII), // + DUP2_X1(I_DUP2_X1.class, PopSpec.III, PushSpec.IIIII), // + DUP2_X2(I_DUP2_X2.class, PopSpec.IIII, PushSpec.IIIIII), // + SWAP(I_SWAP.class, PopSpec.II, PushSpec.II), // ..., value2, value1 => ..., value1, + // value2 + IADD(I_IADD.class, PopSpec.II, PushSpec.I, Operator.Add), // + LADD(I_LADD.class, PopSpec.LL, PushSpec.L, Operator.Add), // + FADD(I_FADD.class, PopSpec.FF, PushSpec.F, Operator.Add), // + DADD(I_DADD.class, PopSpec.DD, PushSpec.D, Operator.Add), // + ISUB(I_ISUB.class, PopSpec.II, PushSpec.I, Operator.Sub), // + LSUB(I_LSUB.class, PopSpec.LL, PushSpec.L, Operator.Sub), // + FSUB(I_FSUB.class, PopSpec.FF, PushSpec.F, Operator.Sub), // + DSUB(I_DSUB.class, PopSpec.DD, PushSpec.D, Operator.Sub), // + IMUL(I_IMUL.class, PopSpec.II, PushSpec.I, Operator.Mul), // + LMUL(I_LMUL.class, PopSpec.LL, PushSpec.L, Operator.Mul), // + FMUL(I_FMUL.class, PopSpec.FF, PushSpec.F, Operator.Mul), // + DMUL(I_DMUL.class, PopSpec.DD, PushSpec.D, Operator.Mul), // + IDIV(I_IDIV.class, PopSpec.II, PushSpec.I, Operator.Div), // + LDIV(I_LDIV.class, PopSpec.LL, PushSpec.L, Operator.Div), // + FDIV(I_FDIV.class, PopSpec.FF, PushSpec.F, Operator.Div), // + DDIV(I_DDIV.class, PopSpec.DD, PushSpec.D, Operator.Div), // + IREM(I_IREM.class, PopSpec.II, PushSpec.I, Operator.Rem), // + LREM(I_LREM.class, PopSpec.LL, PushSpec.L, Operator.Rem), // + FREM(I_FREM.class, PopSpec.FF, PushSpec.F, Operator.Rem), // + DREM(I_DREM.class, PopSpec.DD, PushSpec.D, Operator.Rem), // + INEG(I_INEG.class, PopSpec.I, PushSpec.I, Operator.Neg), // + LNEG(I_LNEG.class, PopSpec.L, PushSpec.L, Operator.Neg), // + FNEG(I_FNEG.class, PopSpec.F, PushSpec.F, Operator.Neg), // + DNEG(I_DNEG.class, PopSpec.D, PushSpec.D, Operator.Neg), // + ISHL(I_ISHL.class, PopSpec.II, PushSpec.I, Operator.LeftShift), // + LSHL(I_LSHL.class, PopSpec.LI, PushSpec.L, Operator.LeftShift), // + ISHR(I_ISHR.class, PopSpec.II, PushSpec.I, Operator.LogicalRightShift), // + LSHR(I_LSHR.class, PopSpec.LI, PushSpec.L, Operator.LogicalRightShift), // + IUSHR(I_IUSHR.class, PopSpec.II, PushSpec.I, Operator.ArithmeticRightShift), // + LUSHR(I_LUSHR.class, PopSpec.LI, PushSpec.L, Operator.ArithmeticRightShift), // + IAND(I_IAND.class, PopSpec.II, PushSpec.I, Operator.BitwiseAnd), // + LAND(I_LAND.class, PopSpec.LL, PushSpec.L, Operator.BitwiseAnd), // + IOR(I_IOR.class, PopSpec.II, PushSpec.I, Operator.BitwiseOr), // + LOR(I_LOR.class, PopSpec.LL, PushSpec.L, Operator.BitwiseOr), // + IXOR(I_IXOR.class, PopSpec.II, PushSpec.I, Operator.BitwiseXor), // + LXOR(I_LXOR.class, PopSpec.LL, PushSpec.L, Operator.BitwiseXor), // + IINC(I_IINC.class, ImmediateSpec.BlvtiBconst), // + I2L(I_I2L.class, PopSpec.I, PushSpec.L, Operator.I2LCast), // + I2F(I_I2F.class, PopSpec.I, PushSpec.F, Operator.I2FCast), // + I2D(I_I2D.class, PopSpec.I, PushSpec.D, Operator.I2DCast), // + L2I(I_L2I.class, PopSpec.L, PushSpec.I, Operator.L2ICast), // + L2F(I_L2F.class, PopSpec.L, PushSpec.F, Operator.L2FCast), // + L2D(I_L2D.class, PopSpec.L, PushSpec.D, Operator.L2DCast), // + F2I(I_F2I.class, PopSpec.F, PushSpec.I, Operator.F2ICast), // + F2L(I_F2L.class, PopSpec.F, PushSpec.L, Operator.F2LCast), // + F2D(I_F2D.class, PopSpec.F, PushSpec.D, Operator.F2DCast), // + D2I(I_D2I.class, PopSpec.D, PushSpec.I, Operator.D2ICast), // + D2L(I_D2L.class, PopSpec.D, PushSpec.L, Operator.D2LCast), // + D2F(I_D2F.class, PopSpec.D, PushSpec.F, Operator.D2FCast), // + I2B(I_I2B.class, PopSpec.I, PushSpec.I, Operator.I2BCast), // + I2C(I_I2C.class, PopSpec.I, PushSpec.I, Operator.I2CCast), // + I2S(I_I2S.class, PopSpec.I, PushSpec.I, Operator.I2SCast), // + LCMP(I_LCMP.class, PopSpec.LL, PushSpec.I, Operator.Sub), // + FCMPL(I_FCMPL.class, PopSpec.FF, PushSpec.I, Operator.LessThan), // + FCMPG(I_FCMPG.class, PopSpec.FF, PushSpec.I, Operator.GreaterThan), // + DCMPL(I_DCMPL.class, PopSpec.DD, PushSpec.I, Operator.LessThan), // + DCMPG(I_DCMPG.class, PopSpec.DD, PushSpec.I, Operator.GreaterThan), // + IFEQ(I_IFEQ.class, ImmediateSpec.Spc, PopSpec.I, Operator.Equal), // + IFNE(I_IFNE.class, ImmediateSpec.Spc, PopSpec.I, Operator.NotEqual), // + IFLT(I_IFLT.class, ImmediateSpec.Spc, PopSpec.I, Operator.LessThan), // + IFGE(I_IFGE.class, ImmediateSpec.Spc, PopSpec.I, Operator.GreaterThanOrEqual), // + IFGT(I_IFGT.class, ImmediateSpec.Spc, PopSpec.I, Operator.GreaterThan), // + IFLE(I_IFLE.class, ImmediateSpec.Spc, PopSpec.I, Operator.LessThanOrEqual), // + IF_ICMPEQ(I_IF_ICMPEQ.class, ImmediateSpec.Sconst, PopSpec.II, Operator.Equal), // + IF_ICMPNE(I_IF_ICMPNE.class, ImmediateSpec.Spc, PopSpec.II, Operator.NotEqual), // + IF_ICMPLT(I_IF_ICMPLT.class, ImmediateSpec.Spc, PopSpec.II, Operator.LessThan), // + IF_ICMPGE(I_IF_ICMPGE.class, ImmediateSpec.Spc, PopSpec.II, Operator.GreaterThanOrEqual), // + IF_ICMPGT(I_IF_ICMPGT.class, ImmediateSpec.Spc, PopSpec.II, Operator.GreaterThan), // + IF_ICMPLE(I_IF_ICMPLE.class, ImmediateSpec.Spc, PopSpec.II, Operator.LessThanOrEqual), // + IF_ACMPEQ(I_IF_ACMPEQ.class, ImmediateSpec.Spc, PopSpec.OO, Operator.Equal), // + IF_ACMPNE(I_IF_ACMPNE.class, ImmediateSpec.Spc, PopSpec.OO, Operator.NotEqual), // + GOTO(I_GOTO.class, ImmediateSpec.Spc), // + JSR(I_JSR.class, ImmediateSpec.Spc, PushSpec.RA), // + RET(I_RET.class, ImmediateSpec.Bconst), // + TABLESWITCH(I_TABLESWITCH.class, ImmediateSpec.UNKNOWN, PopSpec.I), // + LOOKUPSWITCH(I_LOOKUPSWITCH.class, ImmediateSpec.UNKNOWN, PopSpec.I), // + IRETURN(I_IRETURN.class, PopSpec.I), // + LRETURN(I_LRETURN.class, PopSpec.L), // + FRETURN(I_FRETURN.class, PopSpec.F), // + DRETURN(I_DRETURN.class, PopSpec.D), // + ARETURN(I_ARETURN.class, PopSpec.O), // + RETURN(I_RETURN.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, PopSpec.NONE, PushSpec.NONE, Operator.NONE), // + GETSTATIC(I_GETSTATIC.class, ImmediateSpec.Scpfi, PushSpec.UNKNOWN), // + PUTSTATIC(I_PUTSTATIC.class, ImmediateSpec.Scpfi, PopSpec.UNKNOWN), // + GETFIELD(I_GETFIELD.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpfi, PopSpec.O, PushSpec.UNKNOWN, Operator.NONE), // + PUTFIELD(I_PUTFIELD.class, ImmediateSpec.Scpfi, PopSpec.OUNKNOWN), // + INVOKEVIRTUAL(I_INVOKEVIRTUAL.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpmi, PopSpec.OARGS, PushSpec.UNKNOWN, + Operator.NONE), // + INVOKESPECIAL(I_INVOKESPECIAL.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpmi, PopSpec.OARGS, PushSpec.UNKNOWN, + Operator.NONE), // + INVOKESTATIC(I_INVOKESTATIC.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpmi, PopSpec.ARGS, PushSpec.UNKNOWN, + Operator.NONE), // + INVOKEINTERFACE(I_INVOKEINTERFACE.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.ScpmiBB, PopSpec.OARGS, + PushSpec.UNKNOWN, Operator.NONE), // + INVOKEDYNAMIC(I_INVOKEDYNAMIC.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.ScpmiBB, PopSpec.OARGS, PushSpec.UNKNOWN, + Operator.NONE), // + + NEW(I_NEW.class, ImmediateSpec.Scpci, PushSpec.O), // + NEWARRAY(I_NEWARRAY.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Bconst, PopSpec.I, PushSpec.A, Operator.NONE), // + ANEWARRAY(I_ANEWARRAY.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Sconst, PopSpec.I, PushSpec.A, Operator.NONE), // 189 + ARRAYLENGTH(I_ARRAYLENGTH.class, PopSpec.A, PushSpec.I), // 190 + ATHROW(I_ATHROW.class, PopSpec.O, PushSpec.O), // 191 + CHECKCAST(I_CHECKCAST.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpci, PopSpec.O, PushSpec.O, Operator.NONE), // 192 + INSTANCEOF(I_INSTANCEOF.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.Scpci, PopSpec.O, PushSpec.I, Operator.NONE), // 193 + MONITORENTER(I_MONITORENTER.class, PopSpec.O), // 194 + MONITOREXIT(I_MONITOREXIT.class, PopSpec.O), // 195 + WIDE(I_WIDE.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.UNKNOWN, PopSpec.UNKNOWN, PushSpec.UNKNOWN, Operator.NONE), // 196 + MULTIANEWARRAY(I_MULTIANEWARRAY.class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.ScpciBdim, PopSpec.UNKNOWN, PushSpec.A, + Operator.NONE), // 197 + IFNULL(I_IFNULL.class, ImmediateSpec.Spc, PopSpec.O, Operator.EqualNULL), // 198 + IFNONNULL(I_IFNONNULL.class, ImmediateSpec.Spc, PopSpec.O, Operator.NotEqualNULL), // 199 + GOTO_W(I_GOTO_W.class, ImmediateSpec.Ipc), // 200 + JSR_W(I_JSR_W.class, ImmediateSpec.Ipc, PushSpec.RA), // 201 + ILLEGAL_202, // BREAKPOINT("breakpoint"), + ILLEGAL_203, // LDC_QUICK("ldc_quick"), + ILLEGAL_204, // LDC_W_QUICK("ldc_w_quick"), + ILLEGAL_205, // LDC2_W_QUICK("ldc2_w_quick"), + ILLEGAL_206, // GETFIELD_QUICK("getfield_quick"), + ILLEGAL_207, // PUTFIELD_QUICK("putfield_quick"), + ILLEGAL_208, // GETFIELD2_QUICK("getfield2_quick"), + ILLEGAL_209, // PUTFIELD2_QUICK("putfield2_quick"), + ILLEGAL_210, // GETSTATIC_QUICK("getstatic_quick"), + ILLEGAL_211, // PUTSTATIC_QUICK("putstatic_quick"), + ILLEGAL_212, // GETSTATIC2_QUICK("getstatic2_quick"), + ILLEGAL_213, // PUTSTATIC2_QUICK("putstatic2_quick"), + ILLEGAL_214, // INVOKEVIRTUAL_QUICK("invokevirtual_quick"), + ILLEGAL_215, // INVOKENONVIRTUAL_QUICK("invokenonvirtual_quick"), + ILLEGAL_216, // INVOKESUPER_QUICK("invokesuper_quick"), + ILLEGAL_217, // INVOKESTATIC_QUICK("invokestatic_quick"), + ILLEGAL_218, // INVOKEINTERFACE_QUICK("invokeinterface_quick"), + ILLEGAL_219, // INVOKEVIRTUALOBJECT_QUICK("invokevirtualobject_quick"), + ILLEGAL_220, // 220 + ILLEGAL_221, // NEW_QUICK("new_quick"), + ILLEGAL_222, // ANEWARRAY_QUICK("anewarray_quick"), + ILLEGAL_223, // MULTIANEWARRAY_QUICK("multianewarray_quick"), + ILLEGAL_224, // CHECKCAST_QUICK("checkcast_quick"), + ILLEGAL_225, // INSTANCEOF_QUICK("instanceof_quick"), + ILLEGAL_226, // INVOKEVIRTUAL_QUICK_W("invokevirtual_quick_w"), + ILLEGAL_227, // GETFIELD_QUICK_W("getfield_quick_w"), + ILLEGAL_228, // PUTFIELD_QUICK_W("putfield_quick_w"), + ILLEGAL_229, // + ILLEGAL_230, // + ILLEGAL_231, // + ILLEGAL_232, // + ILLEGAL_233, // + ILLEGAL_234, // + ILLEGAL_235, // + ILLEGAL_236, // + ILLEGAL_237, // + ILLEGAL_238, // + ILLEGAL_239, // + ILLEGAL_240, // + ILLEGAL_241, // + ILLEGAL_242, // + ILLEGAL_243, // + ILLEGAL_244, // + ILLEGAL_245, // + ILLEGAL_246, // + ILLEGAL_247, // + ILLEGAL_248, // + ILLEGAL_249, // + ILLEGAL_250, // + ILLEGAL_251, // + ILLEGAL_252, // + ILLEGAL_253, // + ILLEGAL_254, // IMPDEP1("impdep1"), + ILLEGAL_255, // IMPDEP2("impdep2"), + NONE, // + COMPOSITE_IF, // + COMPOSITE_IF_ELSE, // + COMPOSITE_FOR_SUN, // + COMPOSITE_FOR_ECLIPSE, // + COMPOSITE_ARBITRARY_SCOPE, // + COMPOSITE_WHILE, // + CLONE, // + INCREMENT, // + INLINE_ASSIGN, // + MULTI_ASSIGN, // + FAKEGOTO, // + FIELD_ARRAY_ELEMENT_INCREMENT, // + FIELD_ARRAY_ELEMENT_ASSIGN, // + HEAD, // + COMPOSITE_EMPTY_LOOP, // + COMPOSITE_DO_WHILE; + + private final Class<?> clazz; + + private final ImmediateSpec immediate; + + private final PushSpec push; + + private final PopSpec pop; + + private final Operator operator; + + private LoadSpec loadSpec; + + private StoreSpec storeSpec; + + private Constructor<?> constructor; + + private ByteCode(Class<?> _class, LoadSpec _loadSpec, StoreSpec _storeSpec, ImmediateSpec _immediate, PopSpec _pop, + PushSpec _push, Operator _operator) { + clazz = _class; + immediate = _immediate; + push = _push; + pop = _pop; + operator = _operator; + + loadSpec = _loadSpec; + storeSpec = _storeSpec; + if (clazz != null) { + + try { + constructor = clazz.getDeclaredConstructor(MethodModel.class, ByteReader.class, boolean.class); + } catch (final SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final NoSuchMethodException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + private ByteCode(Class<?> _class, ImmediateSpec _immediate) { + this(_class, LoadSpec.NONE, StoreSpec.NONE, _immediate, PopSpec.NONE, PushSpec.NONE, Operator.NONE); + } + + private ByteCode(Class<?> _class, PushSpec _push) { + this(_class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, PopSpec.NONE, _push, Operator.NONE); + } + + private ByteCode(Class<?> _class, StoreSpec _store, ImmediateSpec _immediate, PopSpec _pop) { + this(_class, LoadSpec.NONE, _store, _immediate, _pop, PushSpec.NONE, Operator.NONE); + } + + private ByteCode(Class<?> _class, StoreSpec _store, PopSpec _pop) { + this(_class, LoadSpec.NONE, _store, ImmediateSpec.NONE, _pop, PushSpec.NONE, Operator.NONE); + } + + private ByteCode(Class<?> _class, ImmediateSpec _immediate, PopSpec _pop) { + this(_class, LoadSpec.NONE, StoreSpec.NONE, _immediate, _pop, PushSpec.NONE, Operator.NONE); + } + + private ByteCode(Class<?> _class, ImmediateSpec _immediate, PopSpec _pop, Operator _operator) { + this(_class, LoadSpec.NONE, StoreSpec.NONE, _immediate, _pop, PushSpec.NONE, _operator); + } + + private ByteCode(Class<?> _class, LoadSpec _load, ImmediateSpec _immediate, PushSpec _push) { + this(_class, _load, StoreSpec.NONE, _immediate, PopSpec.NONE, _push, Operator.NONE); + } + + private ByteCode(Class<?> _class, LoadSpec _load, PushSpec _push) { + this(_class, _load, StoreSpec.NONE, ImmediateSpec.NONE, PopSpec.NONE, _push, Operator.NONE); + } + + private ByteCode(Class<?> _class, ImmediateSpec _immediate, PushSpec _push) { + this(_class, LoadSpec.NONE, StoreSpec.NONE, _immediate, PopSpec.NONE, _push, Operator.NONE); + } + + private ByteCode(Class<?> _class, PopSpec _pop, PushSpec _push) { + this(_class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, _pop, _push, Operator.NONE); + } + + private ByteCode(Class<?> _class, PopSpec _pop, PushSpec _push, Operator _operator) { + this(_class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, _pop, _push, _operator); + } + + private ByteCode(Class<?> _class, PopSpec _pop) { + this(_class, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, _pop, PushSpec.NONE, Operator.NONE); + } + + private ByteCode() { + this(null, LoadSpec.NONE, StoreSpec.NONE, ImmediateSpec.NONE, PopSpec.NONE, PushSpec.NONE, Operator.NONE); + } + + public int getCode() { + return (ordinal()); + } + + public String getName() { + return (name().toLowerCase()); + } + + public ImmediateSpec getImmediate() { + return (immediate); + } + + public static ByteCode get(int _idx) { + return (values()[_idx]); + } + + public PushSpec getPush() { + return (push); + } + + public PopSpec getPop() { + return (pop); + } + + // Note I am intentionally skipping PushSpec.LorD. + public boolean usesDouble() { + final PushSpec push = getPush(); + final PopSpec pop = getPop(); + + if ((push == PushSpec.D) || (pop == PopSpec.D) || (pop == PopSpec.DD) || (pop == PopSpec.AID)) { + return true; + } + + return false; + } + + public Instruction newInstruction(MethodModel _methodModel, ByteReader byteReader, boolean _isWide) { + Instruction newInstruction = null; + if (constructor != null) { + try { + newInstruction = (Instruction) constructor.newInstance(_methodModel, byteReader, _isWide); + newInstruction.setLength(byteReader.getOffset() - newInstruction.getThisPC()); + } catch (final SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + return (newInstruction); + } + + public static Instruction create(MethodModel _methodModel, ByteReader _byteReader) { + ByteCode byteCode = get(_byteReader.u1()); + boolean isWide = false; + + if (byteCode.equals(ByteCode.WIDE)) { + // handle wide + //System.out.println("WIDE"); + isWide = true; + byteCode = get(_byteReader.u1()); + } + + final Instruction newInstruction = byteCode.newInstruction(_methodModel, _byteReader, isWide); + + return (newInstruction); + } + + public Operator getOperator() { + return (operator); + } + + public LoadSpec getLoad() { + return (loadSpec); + } + + public StoreSpec getStore() { + return (storeSpec); + } + } + + public static class CompositeInstruction extends Instruction{ + + protected BranchSet branchSet; + + public CompositeInstruction(MethodModel method, ByteCode _byteCode, Instruction _firstChild, Instruction _lastChild, + BranchSet _branchSet) { + super(method, _byteCode, -1); + branchSet = _branchSet; + setChildren(_firstChild, _lastChild); + } + + @Override public String getDescription() { + return ("COMPOSITE! " + getByteCode()); + } + + @Override public int getThisPC() { + return (getLastChild().getThisPC()); + } + + @Override public int getStartPC() { + return (getFirstChild().getStartPC()); + } + + public static CompositeInstruction create(ByteCode _byteCode, MethodModel _methodModel, Instruction _firstChild, + Instruction _lastChild, BranchSet _branchSet) { + CompositeInstruction compositeInstruction = null; + switch (_byteCode) { + case COMPOSITE_IF: + compositeInstruction = new CompositeIfInstruction(_methodModel, _firstChild, _lastChild, _branchSet); + break; + case COMPOSITE_IF_ELSE: + compositeInstruction = new CompositeIfElseInstruction(_methodModel, _firstChild, _lastChild, _branchSet); + break; + case COMPOSITE_FOR_SUN: + compositeInstruction = new CompositeForSunInstruction(_methodModel, _firstChild, _lastChild, _branchSet); + break; + case COMPOSITE_WHILE: + compositeInstruction = new CompositeWhileInstruction(_methodModel, _firstChild, _lastChild, _branchSet); + break; + case COMPOSITE_FOR_ECLIPSE: + compositeInstruction = new CompositeForEclipseInstruction(_methodModel, _firstChild, _lastChild, _branchSet); + break; + case COMPOSITE_ARBITRARY_SCOPE: + compositeInstruction = new CompositeArbitraryScopeInstruction(_methodModel, _firstChild, _lastChild, _branchSet); + break; + case COMPOSITE_EMPTY_LOOP: + compositeInstruction = new CompositeEmptyLoopInstruction(_methodModel, _firstChild, _lastChild, _branchSet); + break; + case COMPOSITE_DO_WHILE: + compositeInstruction = new CompositeDoWhileInstruction(_methodModel, _firstChild, _lastChild, _branchSet); + break; + } + + return (compositeInstruction); + } + + public BranchSet getBranchSet() { + return (branchSet); + } + } + + public static class CompositeIfInstruction extends CompositeInstruction{ + public CompositeIfInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, BranchSet _branchSet) { + super(method, ByteCode.COMPOSITE_IF, _firstChild, _lastChild, _branchSet); + } + } + + public static class CompositeIfElseInstruction extends CompositeInstruction{ + public CompositeIfElseInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, BranchSet _branchSet) { + super(method, ByteCode.COMPOSITE_IF_ELSE, _firstChild, _lastChild, _branchSet); + } + } + + public static class CompositeForSunInstruction extends CompositeInstruction{ + public CompositeForSunInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, BranchSet _branchSet) { + super(method, ByteCode.COMPOSITE_FOR_SUN, _firstChild, _lastChild, _branchSet); + } + } + + public static class CompositeWhileInstruction extends CompositeInstruction{ + public CompositeWhileInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, BranchSet _branchSet) { + super(method, ByteCode.COMPOSITE_WHILE, _firstChild, _lastChild, _branchSet); + } + } + + public static class CompositeEmptyLoopInstruction extends CompositeInstruction{ + public CompositeEmptyLoopInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, BranchSet _branchSet) { + super(method, ByteCode.COMPOSITE_EMPTY_LOOP, _firstChild, _lastChild, _branchSet); + } + } + + public static class CompositeDoWhileInstruction extends CompositeInstruction{ + + protected CompositeDoWhileInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, + BranchSet _branchSet) { + super(method, ByteCode.COMPOSITE_DO_WHILE, _firstChild, _lastChild, _branchSet); + } + } + + public static class CompositeForEclipseInstruction extends CompositeInstruction{ + protected CompositeForEclipseInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, + BranchSet _branchSet) { + super(method, ByteCode.COMPOSITE_FOR_ECLIPSE, _firstChild, _lastChild, _branchSet); + + } + } + + public static class CompositeArbitraryScopeInstruction extends CompositeInstruction{ + protected CompositeArbitraryScopeInstruction(MethodModel method, Instruction _firstChild, Instruction _lastChild, + BranchSet _branchSet) { + super(method, ByteCode.COMPOSITE_ARBITRARY_SCOPE, _firstChild, _lastChild, _branchSet); + } + } + + public static abstract class OperatorInstruction extends Instruction{ + protected OperatorInstruction(MethodModel _methodPoolEntry, ByteCode code, ByteReader reader, boolean _wide) { + super(_methodPoolEntry, code, reader, _wide); + } + + public Operator getOperator() { + return (getByteCode().getOperator()); + } + } + + public static abstract class BinaryOperator extends OperatorInstruction implements Binary{ + @Override public final Instruction getLhs() { + return (getFirstChild()); + } + + @Override public final Instruction getRhs() { + return (getLastChild()); + } + + protected BinaryOperator(MethodModel _methodPoolEntry, ByteCode code, ByteReader reader, boolean _wide) { + super(_methodPoolEntry, code, reader, _wide); + } + } + + public static abstract class UnaryOperator extends OperatorInstruction implements Unary{ + @Override public final Instruction getUnary() { + return (getFirstChild()); + } + + protected UnaryOperator(MethodModel _methodPoolEntry, ByteCode code, ByteReader reader, boolean _wide) { + super(_methodPoolEntry, code, reader, _wide); + } + } + + public static abstract class CastOperator extends UnaryOperator{ + protected CastOperator(MethodModel _methodPoolEntry, ByteCode code, ByteReader reader, boolean _wide) { + super(_methodPoolEntry, code, reader, _wide); + } + } + + public static abstract class Branch extends Instruction{ + protected int offset; + + protected boolean breakOrContinue; + + protected Instruction target; + + public int getAbsolute() { + return (getThisPC() + getOffset()); + } + + private int getOffset() { + return (offset); + } + + public Branch(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + + public Branch(MethodModel _methodPoolEntry, ByteCode _byteCode, Instruction _target) { + super(_methodPoolEntry, _byteCode, -1); + setTarget(_target); + } + + public Instruction getTarget() { + return (target); + } + + public void setTarget(Instruction _target) { + target = _target; + offset = target.getThisPC() - getThisPC(); + target.addBranchTarget(this); + } + + public boolean isConditional() { + return (this instanceof ConditionalBranch); + } + + public boolean isUnconditional() { + return (this instanceof UnconditionalBranch); + } + + public boolean isReverseConditional() { + return (isConditional() && isReverse()); + } + + public boolean isForwardConditional() { + return (isConditional() && isForward()); + } + + public boolean isReverseUnconditional() { + return (isUnconditional() && isReverse()); + } + + public boolean isForwardUnconditional() { + return (isUnconditional() && isForward()); + } + + public boolean isReverse() { + return (offset < 0); + } + + public boolean isForward() { + return (offset >= 0); + } + + public void unhook() { + getTarget().removeBranchTarget(this); + } + + public void setBreakOrContinue(boolean b) { + breakOrContinue = true; + } + + public boolean isBreakOrContinue() { + return (breakOrContinue); + } + + public void retarget(Instruction _newTarget) { + //System.out.println("retargetting " + pc + " -> " + target.getThisPC() + " to " + _newTarget.getThisPC()); + unhook(); // removes this from the list of branchers to target + setTarget(_newTarget); + //System.out.println("retargetted " + pc + " -> " + target.getThisPC()); + // _newTarget.addBranchTarget(this); + } + } + + public static abstract class ConditionalBranch extends Branch{ + private BranchSet branchSet; + + public ConditionalBranch(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + + public void setBranchSet(BranchSet _branchSet) { + branchSet = _branchSet; + } + + public BranchSet getOrCreateBranchSet() { + if (branchSet == null) { + branchSet = new BranchSet(this); + } + + return branchSet; + } + + public BranchSet getBranchSet() { + return branchSet; + } + + // extent is a guess but we know that the target will be beyond extent, we are not interested in targets that fall before extent + public ConditionalBranch findEndOfConditionalBranchSet(Instruction _extent) { + // bummer ;) + // we need to find the actual branch set. Be careful here we can only create a branch set when we *know* that a conditional is the last in the set. + // we don't know that here. We have to scan forward to try to find it + ConditionalBranch i = this; + Instruction theTarget = null; + ConditionalBranch lastToTarget = null; + + if (getTarget().isAfter(_extent)) { + // if this conditional is already pointing beyond extent then we know the target + theTarget = getTarget(); + lastToTarget = this; + } + + while (i.getNextExpr().isBranch() && i.getNextExpr().asBranch().isForwardConditional()) { + final Branch nextBranch = i.getNextExpr().asBranch(); + + if ((theTarget == null) && nextBranch.getTarget().isAfter(_extent)) { + theTarget = nextBranch.getTarget(); + lastToTarget = this; + } else if (nextBranch.getTarget() == theTarget) { + lastToTarget = this; + } + + i = (ConditionalBranch) i.getNextExpr(); + } + + if (theTarget == null) { + throw new IllegalStateException("unable to find end of while extent"); + } + + return (lastToTarget); + } + } + + public static abstract class UnconditionalBranch extends Branch{ + public UnconditionalBranch(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + + public UnconditionalBranch(MethodModel _methodPoolEntry, ByteCode _byteCode, Instruction _target) { + super(_methodPoolEntry, _byteCode, _target); + } + } + + public static abstract class IfUnary extends ConditionalBranch16 implements Unary{ + public IfUnary(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + + @Override public Instruction getUnary() { + return (getFirstChild()); + } + } + + public static abstract class If extends ConditionalBranch16 implements Binary{ + public If(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + + @Override public Instruction getLhs() { + return (getFirstChild()); + } + + @Override public Instruction getRhs() { + return (getLastChild()); + } + } + + public static abstract class ConditionalBranch16 extends ConditionalBranch implements HasOperator{ + public ConditionalBranch16(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + offset = _byteReader.s2(); + } + + @Override public Operator getOperator() { + return (getByteCode().getOperator()); + } + } + + public static abstract class UnconditionalBranch16 extends UnconditionalBranch{ + public UnconditionalBranch16(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + offset = _byteReader.s2(); + } + } + + public static abstract class Branch32 extends UnconditionalBranch{ + public Branch32(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + offset = _byteReader.s4(); + } + } + + public static abstract class ArrayAccess extends Instruction{ + public ArrayAccess(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + + public Instruction getArrayRef() { + return (getFirstChild()); + } + + public Instruction getArrayIndex() { + return (getFirstChild().getNextExpr()); + } + } + + public static abstract class AccessArrayElement extends ArrayAccess{ + protected AccessArrayElement(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + } + + public static class I_AALOAD extends AccessArrayElement{ + public I_AALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.AALOAD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push reference from arrayref and index"); + } + } + + public static abstract class AssignToArrayElement extends ArrayAccess{ + public Instruction getValue() { + return (getFirstChild().getNextExpr().getNextExpr()); + } + + protected AssignToArrayElement(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + } + + public static class I_AASTORE extends AssignToArrayElement{ + public I_AASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.AASTORE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop reference into arrayref[index]"); + } + } + + public static class I_ACONST_NULL extends Instruction implements Constant<Object>{ + public I_ACONST_NULL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ACONST_NULL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push null"); + } + + @Override public Object getValue() { + return null; + } + } + + public static abstract class LocalVariableConstIndexAccessor extends IndexConst implements AccessLocalVariable{ + public LocalVariableConstIndexAccessor(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide, + int index) { + super(methodPoolEntry, byteCode, byteReader, _wide, index); + } + + @Override public int getLocalVariableTableIndex() { + return (index); + } + + @Override public LocalVariableInfo getLocalVariableInfo() { + return (method.getLocalVariableTableEntry().getVariable(getThisPC() + getLength(), getLocalVariableTableIndex())); + } + } + + public static abstract class LocalVariableConstIndexLoad extends LocalVariableConstIndexAccessor{ + public LocalVariableConstIndexLoad(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide, + int index) { + super(methodPoolEntry, byteCode, byteReader, _wide, index); + } + + @Override public String getDescription() { + return ("push reference from local var index " + index); + } + } + + public static abstract class LocalVariableConstIndexStore extends LocalVariableConstIndexAccessor implements + AssignToLocalVariable{ + public LocalVariableConstIndexStore(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide, + int index) { + super(methodPoolEntry, byteCode, byteReader, _wide, index); + } + + @Override public boolean isDeclaration() { + LocalVariableInfo lvi = method.getLocalVariableTableEntry().getVariable(getThisPC() + getLength(), + getLocalVariableTableIndex()); + return (lvi.getStart() == getThisPC() + getLength()); + } + + @Override public String getDescription() { + return ("pop reference into local var index " + index); + } + } + + public static abstract class LocalVariableIndex08Accessor extends Index08 implements AccessLocalVariable{ + public LocalVariableIndex08Accessor(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide) { + super(methodPoolEntry, byteCode, byteReader, _wide); + } + + @Override public int getLocalVariableTableIndex() { + return (index); + } + + @Override public LocalVariableInfo getLocalVariableInfo() { + return (method.getLocalVariableTableEntry().getVariable(getThisPC() + getLength(), getLocalVariableTableIndex())); + } + } + + public static abstract class LocalVariableIndex08Load extends LocalVariableIndex08Accessor{ + public LocalVariableIndex08Load(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide) { + super(methodPoolEntry, byteCode, byteReader, _wide); + } + + @Override public String getDescription() { + return ("push reference from local var index " + index); + } + } + + public static abstract class LocalVariableIndex08Store extends LocalVariableIndex08Accessor implements AssignToLocalVariable{ + public LocalVariableIndex08Store(MethodModel methodPoolEntry, ByteCode byteCode, ByteReader byteReader, boolean _wide) { + super(methodPoolEntry, byteCode, byteReader, _wide); + } + + @Override public boolean isDeclaration() { + final LocalVariableTableEntry localVariableTableEntry = method.getLocalVariableTableEntry(); + final LocalVariableInfo localVarInfo = localVariableTableEntry.getVariable(getThisPC() + getLength(), + getLocalVariableTableIndex()); + return ((localVarInfo != null) && (localVarInfo.getStart() == (getThisPC() + getLength()))); + } + + @Override public String getDescription() { + return ("pop reference into local var index " + index); + } + } + + public static class I_ALOAD extends LocalVariableIndex08Load{ + public I_ALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ALOAD, _byteReader, _wide); + } + } + + public static class I_ALOAD_0 extends LocalVariableConstIndexLoad{ + public I_ALOAD_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ALOAD_0, _byteReader, _wide, 0); + } + } + + public static class I_ALOAD_1 extends LocalVariableConstIndexLoad{ + public I_ALOAD_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ALOAD_1, _byteReader, _wide, 1); + } + } + + public static class I_ALOAD_2 extends LocalVariableConstIndexLoad{ + public I_ALOAD_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ALOAD_2, _byteReader, _wide, 2); + } + } + + public static class I_ALOAD_3 extends LocalVariableConstIndexLoad{ + public I_ALOAD_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ALOAD_3, _byteReader, _wide, 3); + } + } + + public static class I_ANEWARRAY extends Index16 implements New{ + public I_ANEWARRAY(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ANEWARRAY, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("new array of reference"); + } + } + + public static class I_ARETURN extends Return{ + public I_ARETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ARETURN, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("return popped reference"); + } + } + + public static class I_ARRAYLENGTH extends Instruction{ + public I_ARRAYLENGTH(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ARRAYLENGTH, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop array push length"); + } + } + + public static class I_ASTORE extends LocalVariableIndex08Store{ + public I_ASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ASTORE, _byteReader, _wide); + } + } + + public static class I_ASTORE_0 extends LocalVariableConstIndexStore{ + public I_ASTORE_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ASTORE_0, _byteReader, _wide, 0); + } + } + + public static class I_ASTORE_1 extends LocalVariableConstIndexStore{ + public I_ASTORE_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ASTORE_1, _byteReader, _wide, 1); + } + } + + public static class I_ASTORE_2 extends LocalVariableConstIndexStore{ + public I_ASTORE_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ASTORE_2, _byteReader, _wide, 2); + } + } + + public static class I_ASTORE_3 extends LocalVariableConstIndexStore{ + public I_ASTORE_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ASTORE_3, _byteReader, _wide, 3); + } + } + + public static class I_ATHROW extends Instruction{ + public I_ATHROW(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ATHROW, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop reference and throw"); + } + } + + public static class I_BALOAD extends AccessArrayElement{ + public I_BALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.BALOAD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push byte/boolean from arrayref and index"); + } + } + + public static class I_BASTORE extends AssignToArrayElement{ + public I_BASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.BASTORE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop boolean/byte into arrayref[index]"); + } + } + + public static class I_BIPUSH extends ImmediateConstant<Integer>{ + public I_BIPUSH(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.BIPUSH, _byteReader, _wide); + value = _byteReader.u1(); + } + + @Override public String getDescription() { + return ("push (byte)"); + } + + @Override public Integer getValue() { + int byteValue = super.getValue(); + if (byteValue > 127) { + byteValue = -(256 - byteValue); + } + return (byteValue); + } + } + + public static class I_CALOAD extends AccessArrayElement{ + public I_CALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.CALOAD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push char from arrayref and index"); + } + } + + public static class I_CASTORE extends AssignToArrayElement{ + public I_CASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.CASTORE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop char into arrayref[index]"); + } + } + + public static class I_CHECKCAST extends Index16{ + public I_CHECKCAST(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.CHECKCAST, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("peek reference check against the constant accessed 16 bit"); + } + } + + public static class I_D2F extends CastOperator{ + public I_D2F(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.D2F, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop double push float"); + } + } + + public static class I_D2I extends CastOperator{ + public I_D2I(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.D2I, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop double push int"); + } + } + + public static class I_D2L extends CastOperator{ + public I_D2L(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.D2L, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop double push long"); + } + } + + public static class I_DADD extends BinaryOperator{ + public I_DADD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DADD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("add top two doubles"); + } + } + + public static class I_DALOAD extends AccessArrayElement{ + public I_DALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DALOAD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push double from arrayref and index"); + } + } + + public static class I_DASTORE extends AssignToArrayElement{ + public I_DASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DASTORE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop double into arrayref[index]"); + } + } + + public static class I_DCMPG extends Instruction{ + public I_DCMPG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DCMPG, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push result of double comparison"); + } + } + + public static class I_DCMPL extends Instruction{ + public I_DCMPL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DCMPL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push result of double comparison"); + } + } + + public static abstract class BytecodeEncodedConstant<T> extends Instruction implements Constant<T>{ + private final T value; + + public BytecodeEncodedConstant(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide, + T _value) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + value = _value; + } + + @Override public T getValue() { + return (value); + } + } + + public static abstract class ImmediateConstant<T> extends Instruction implements Constant<T>{ + protected T value; + + public ImmediateConstant(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + + @Override public T getValue() { + return (value); + } + } + + public static class I_DCONST_0 extends BytecodeEncodedConstant<Double>{ + public I_DCONST_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DCONST_0, _byteReader, _wide, 0.0); + } + + @Override public String getDescription() { + return ("push (double) 0.0"); + } + } + + public static class I_DCONST_1 extends BytecodeEncodedConstant<Double>{ + public I_DCONST_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DCONST_1, _byteReader, _wide, 1.0); + } + + @Override public String getDescription() { + return ("push (double) 1.0"); + } + } + + public static class I_DDIV extends BinaryOperator{ + public I_DDIV(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DDIV, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("div top two doubles"); + } + } + + public static class I_DLOAD extends LocalVariableIndex08Load{ + public I_DLOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DLOAD, _byteReader, _wide); + } + } + + public static class I_DLOAD_0 extends LocalVariableConstIndexLoad{ + public I_DLOAD_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DLOAD_0, _byteReader, _wide, 0); + } + } + + public static class I_DLOAD_1 extends LocalVariableConstIndexLoad{ + public I_DLOAD_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DLOAD_1, _byteReader, _wide, 1); + } + } + + public static class I_DLOAD_2 extends LocalVariableConstIndexLoad{ + public I_DLOAD_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DLOAD_2, _byteReader, _wide, 2); + } + } + + public static class I_DLOAD_3 extends LocalVariableConstIndexLoad{ + public I_DLOAD_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DLOAD_3, _byteReader, _wide, 3); + } + } + + public static class I_DMUL extends BinaryOperator{ + public I_DMUL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DMUL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("mul top two doubles"); + } + } + + public static class I_DNEG extends UnaryOperator{ + public I_DNEG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DNEG, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("neg top double"); + } + } + + public static class I_DREM extends BinaryOperator{ + public I_DREM(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DREM, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("rem top two doubles"); + } + } + + public static class I_DRETURN extends Return{ + public I_DRETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DRETURN, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("return popped double"); + } + } + + public static class I_DSTORE extends LocalVariableIndex08Store{ + public I_DSTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DSTORE, _byteReader, _wide); + } + } + + public static class I_DSTORE_0 extends LocalVariableConstIndexStore{ + public I_DSTORE_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DSTORE_0, _byteReader, _wide, 0); + } + } + + public static class I_DSTORE_1 extends LocalVariableConstIndexStore{ + public I_DSTORE_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DSTORE_1, _byteReader, _wide, 1); + } + } + + public static class I_DSTORE_2 extends LocalVariableConstIndexStore{ + public I_DSTORE_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DSTORE_2, _byteReader, _wide, 2); + } + } + + public static class I_DSTORE_3 extends LocalVariableConstIndexStore{ + public I_DSTORE_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DSTORE_3, _byteReader, _wide, 3); + } + } + + public static class I_DSUB extends BinaryOperator{ + public I_DSUB(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DSUB, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("sub top two doubles"); + } + } + + public static abstract class DUP extends Instruction{ + public DUP(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + } + + public static class I_DUP extends DUP{ + public I_DUP(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DUP, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("dup top item"); + } + } + + public static class I_DUP_X1 extends DUP{ + public I_DUP_X1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DUP_X1, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("dup top item 2 items down"); + } + } + + public static class I_DUP_X2 extends DUP{ + public I_DUP_X2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DUP_X2, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("dup top item 3 items down"); + } + } + + public static class I_DUP2 extends DUP{ + public I_DUP2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DUP2, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("dup top 2 items"); + } + } + + public static class I_DUP2_X1 extends DUP{ + public I_DUP2_X1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DUP2_X1, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("dup top 2 items 2 items down"); + } + } + + public static class I_DUP2_X2 extends DUP{ + public I_DUP2_X2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.DUP_X2, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("dup top 2 items 3 items down"); + } + } + + public static class I_F2D extends CastOperator{ + public I_F2D(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.F2D, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop float push double"); + } + } + + public static class I_F2I extends CastOperator{ + public I_F2I(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.F2I, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop float push int"); + } + } + + public static class I_F2L extends CastOperator{ + public I_F2L(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.F2L, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop float push long"); + } + } + + public static class I_FADD extends BinaryOperator{ + public I_FADD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FADD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("add top two floats"); + } + } + + public static class I_FALOAD extends AccessArrayElement{ + public I_FALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FALOAD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push float from arrayref and index"); + } + } + + public static class I_FASTORE extends AssignToArrayElement{ + public I_FASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FASTORE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop float into arrayref[index]"); + } + } + + public static class I_FCMPG extends BinaryOperator{ + public I_FCMPG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FCMPG, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push result of float comparison"); + } + } + + public static class I_FCMPL extends BinaryOperator{ + public I_FCMPL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FCMPL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push result of float comparison"); + } + } + + public static class I_FCONST_0 extends BytecodeEncodedConstant<Float>{ + public I_FCONST_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FCONST_0, _byteReader, _wide, 0f); + } + + @Override public String getDescription() { + return ("push (float) 0.0"); + } + } + + public static class I_FCONST_1 extends BytecodeEncodedConstant<Float>{ + public I_FCONST_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FCONST_1, _byteReader, _wide, 1f); + } + + @Override public String getDescription() { + return ("push (float) 1.0"); + } + } + + public static class I_FCONST_2 extends BytecodeEncodedConstant<Float>{ + public I_FCONST_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FCONST_2, _byteReader, _wide, 2f); + } + + @Override public String getDescription() { + return ("push (float) 2.0"); + } + } + + public static class I_FDIV extends BinaryOperator{ + public I_FDIV(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FDIV, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("div top two floats"); + } + } + + public static class I_FLOAD extends LocalVariableIndex08Load{ + public I_FLOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FLOAD, _byteReader, _wide); + } + } + + public static class I_FLOAD_0 extends LocalVariableConstIndexLoad{ + public I_FLOAD_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FLOAD_0, _byteReader, _wide, 0); + } + } + + public static class I_FLOAD_1 extends LocalVariableConstIndexLoad{ + public I_FLOAD_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FLOAD_1, _byteReader, _wide, 1); + } + } + + public static class I_FLOAD_2 extends LocalVariableConstIndexLoad{ + public I_FLOAD_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FLOAD_2, _byteReader, _wide, 2); + } + } + + public static class I_FLOAD_3 extends LocalVariableConstIndexLoad{ + public I_FLOAD_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FLOAD_3, _byteReader, _wide, 3); + } + } + + public static class I_FMUL extends BinaryOperator{ + public I_FMUL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FMUL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("mul top two floats"); + } + } + + public static class I_FNEG extends UnaryOperator{ + public I_FNEG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FNEG, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("neg top float"); + } + } + + public static class I_FREM extends BinaryOperator{ + public I_FREM(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FREM, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("rem top two floats"); + } + } + + public static class I_FRETURN extends Return{ + public I_FRETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FRETURN, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("return popped float"); + } + } + + public static class I_FSTORE extends LocalVariableIndex08Store{ + public I_FSTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FSTORE, _byteReader, _wide); + } + } + + public static class I_FSTORE_0 extends LocalVariableConstIndexStore{ + public I_FSTORE_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FSTORE_0, _byteReader, _wide, 0); + } + } + + public static class I_FSTORE_1 extends LocalVariableConstIndexStore{ + public I_FSTORE_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FSTORE_1, _byteReader, _wide, 1); + } + } + + public static class I_FSTORE_2 extends LocalVariableConstIndexStore{ + I_FSTORE_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FSTORE_2, _byteReader, _wide, 2); + } + } + + public static class I_FSTORE_3 extends LocalVariableConstIndexStore{ + public I_FSTORE_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FSTORE_3, _byteReader, _wide, 3); + } + } + + public static class I_FSUB extends BinaryOperator{ + public I_FSUB(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.FSUB, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("sub top two floats"); + } + } + + public static class I_GETFIELD extends Index16 implements AccessInstanceField{ + + public I_GETFIELD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.GETFIELD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push value from field referenced by 16 bit constant index"); + } + + @Override public int getConstantPoolFieldIndex() { + return (index); + } + + @Override public FieldEntry getConstantPoolFieldEntry() { + return (method.getConstantPool().getFieldEntry(getConstantPoolFieldIndex())); + } + + @Override public Instruction getInstance() { + return (getFirstChild()); + } + + @Override public int getStackConsumeCount() { + return (1); + } + + @Override public int getStackProduceCount() { + return (1); + } + } + + public static class I_GETSTATIC extends Index16 implements AccessField{ + public I_GETSTATIC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.GETSTATIC, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push static field value at 16 bit constant index"); + } + + @Override public int getConstantPoolFieldIndex() { + return (index); + } + + @Override public FieldEntry getConstantPoolFieldEntry() { + return (method.getConstantPool().getFieldEntry(getConstantPoolFieldIndex())); + } + + @Override public int getStackConsumeCount() { + return (0); + } + + @Override public int getStackProduceCount() { + return (1); + } + } + + public static class I_GOTO extends UnconditionalBranch16{ + public I_GOTO(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.GOTO, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch "); + } + } + + public static class I_GOTO_W extends Branch32{ + public I_GOTO_W(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.GOTO_W, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("goto wide branch"); + } + } + + public static class I_I2B extends CastOperator{ + public I_I2B(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.I2B, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop int push byte"); + } + } + + public static class I_I2C extends CastOperator{ + public I_I2C(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.I2C, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop int push char"); + } + } + + public static class I_I2D extends CastOperator{ + public I_I2D(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.I2D, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop int push double"); + } + } + + public static class I_I2F extends CastOperator{ + public I_I2F(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.I2F, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop int push float"); + } + } + + public static class I_I2L extends CastOperator{ + public I_I2L(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.I2L, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop int push long"); + } + } + + public static class I_I2S extends CastOperator{ + public I_I2S(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.I2S, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop int push short"); + } + } + + public static class I_IADD extends BinaryOperator{ + public I_IADD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IADD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("add top two ints"); + } + } + + public static class I_IALOAD extends AccessArrayElement{ + public I_IALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IALOAD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push int from arrayref and index"); + } + } + + public static class I_IAND extends BinaryOperator{ + public I_IAND(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IAND, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("and top two ints"); + } + } + + public static class I_IASTORE extends AssignToArrayElement{ + public I_IASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IASTORE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop int into arrayref[index]"); + } + } + + public static class I_ICONST_0 extends BytecodeEncodedConstant<Integer>{ + public I_ICONST_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ICONST_0, _byteReader, _wide, 0); + } + + @Override public String getDescription() { + return ("push (int) 0"); + } + } + + public static class I_ICONST_1 extends BytecodeEncodedConstant<Integer>{ + public I_ICONST_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ICONST_1, _byteReader, _wide, 1); + } + + @Override public String getDescription() { + return ("push (int) 1"); + } + } + + public static class I_ICONST_2 extends BytecodeEncodedConstant<Integer>{ + public I_ICONST_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ICONST_2, _byteReader, _wide, 2); + } + + @Override public String getDescription() { + return ("push (int) 2"); + } + } + + public static class I_ICONST_3 extends BytecodeEncodedConstant<Integer>{ + public I_ICONST_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ICONST_3, _byteReader, _wide, 3); + } + + @Override public String getDescription() { + return ("push (int) 3"); + } + } + + public static class I_ICONST_4 extends BytecodeEncodedConstant<Integer>{ + public I_ICONST_4(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ICONST_4, _byteReader, _wide, 4); + } + + @Override public String getDescription() { + return ("push (int) 4"); + } + } + + public static class I_ICONST_5 extends BytecodeEncodedConstant<Integer>{ + public I_ICONST_5(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ICONST_5, _byteReader, _wide, 5); + } + + @Override public String getDescription() { + return ("push (int) 5"); + } + } + + public static class I_ICONST_M1 extends BytecodeEncodedConstant<Integer>{ + public I_ICONST_M1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ICONST_M1, _byteReader, _wide, -1); + } + + @Override public String getDescription() { + return ("push (int)-1"); + } + } + + public static class I_IDIV extends BinaryOperator{ + public I_IDIV(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IDIV, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("div top two ints"); + } + } + + public static class I_IF_ACMPEQ extends If{ + public I_IF_ACMPEQ(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IF_ACMPEQ, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top references =="); + } + } + + public static class I_IF_ACMPNE extends If{ + public I_IF_ACMPNE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IF_ACMPNE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top references !="); + } + } + + public static class I_IF_ICMPEQ extends If{ + public I_IF_ICMPEQ(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IF_ICMPEQ, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top ints =="); + } + } + + public static class I_IF_ICMPGE extends If{ + public I_IF_ICMPGE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IF_ICMPGE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top ints >="); + } + } + + public static class I_IF_ICMPGT extends If{ + public I_IF_ICMPGT(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IF_ICMPGT, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top ints > "); + } + } + + public static class I_IF_ICMPLE extends If{ + public I_IF_ICMPLE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IF_ICMPLE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top ints <="); + } + } + + public static class I_IF_ICMPLT extends If{ + public I_IF_ICMPLT(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IF_ICMPLT, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top ints < "); + } + } + + public static class I_IF_ICMPNE extends If{ + public I_IF_ICMPNE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IF_ICMPNE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top ints !="); + } + } + + public static class I_IFEQ extends IfUnary{ + public I_IFEQ(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IFEQ, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top int == 0"); + } + } + + public static class I_IFGE extends IfUnary{ + public I_IFGE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IFGE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top int >= 0"); + } + } + + public static class I_IFGT extends IfUnary{ + public I_IFGT(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IFGT, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top int > 0"); + } + } + + public static class I_IFLE extends IfUnary{ + public I_IFLE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IFLE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top int <= 0"); + } + } + + public static class I_IFLT extends IfUnary{ + public I_IFLT(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IFLT, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top int < 0"); + } + } + + public static class I_IFNE extends IfUnary{ + public I_IFNE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IFNE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if stack top int != 0"); + } + } + + public static class I_IFNONNULL extends ConditionalBranch16{ + public I_IFNONNULL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IFNONNULL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if non null"); + } + } + + public static class I_IFNULL extends ConditionalBranch16{ + public I_IFNULL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IFNULL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("branch if null"); + } + } + + public static class I_IINC extends Index08{ + private int delta; + + private final boolean wide; + + public I_IINC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IINC, _byteReader, _wide); + wide = _wide; + if (wide) { + delta = _byteReader.u2(); + } else { + delta = _byteReader.u1(); + } + + } + + @Override public String getDescription() { + return ("inc var index 08 bit by byte"); + } + + public LocalVariableInfo getLocalVariableInfo() { + return (method.getLocalVariableTableEntry().getVariable(getThisPC(), getLocalVariableTableIndex())); + } + + public int getLocalVariableTableIndex() { + return (index); + } + + public int getDelta() { + return (delta); + } + + public boolean isInc() { + return getAdjust() > 0; + } + + public int getAdjust() { + int adjust = delta; + if (wide) { + if (adjust > 0x7fff) { + adjust = -0x10000 + adjust; + } + } else { + if (adjust > 0x7f) { + adjust = -0x100 + adjust; + } + } + return (adjust); + } + } + + public static class I_ILOAD extends LocalVariableIndex08Load{ + public I_ILOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ILOAD, _byteReader, _wide); + } + } + + public static class I_ILOAD_0 extends LocalVariableConstIndexLoad{ + public I_ILOAD_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ILOAD_0, _byteReader, _wide, 0); + } + } + + public static class I_ILOAD_1 extends LocalVariableConstIndexLoad{ + public I_ILOAD_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ILOAD_1, _byteReader, _wide, 1); + } + } + + public static class I_ILOAD_2 extends LocalVariableConstIndexLoad{ + public I_ILOAD_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ILOAD_2, _byteReader, _wide, 2); + } + } + + public static class I_ILOAD_3 extends LocalVariableConstIndexLoad{ + public I_ILOAD_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ILOAD_3, _byteReader, _wide, 3); + } + } + + public static class I_IMUL extends BinaryOperator{ + public I_IMUL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IMUL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("mul top two ints"); + } + } + + public static class I_INEG extends UnaryOperator{ + public I_INEG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.INEG, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("neg top int"); + } + } + + public static class I_INSTANCEOF extends Index16{ + public I_INSTANCEOF(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.INSTANCEOF, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop reference check against the constant accessed 16 bit push 1 if same"); + } + } + + public static class I_INVOKEINTERFACE extends Index16 implements InterfaceConstantPoolMethodIndexAccessor{ + private final int args; + + public I_INVOKEINTERFACE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.INVOKEINTERFACE, _byteReader, _wide); + args = _byteReader.u1(); + @SuppressWarnings("unused") final int zeroByte = _byteReader.u1(); + + } + + @Override public int getArgs() { + return (args); + } + + @Override public String getDescription() { + return ("pop args and call the interface method referenced by 16 bit constant index"); + } + + @Override public int getConstantPoolInterfaceMethodIndex() { + return (index); + } + + @Override public ConstantPool.InterfaceMethodEntry getConstantPoolInterfaceMethodEntry() { + return (method.getConstantPool().getInterfaceMethodEntry(getConstantPoolInterfaceMethodIndex())); + } + + @Override public Instruction getArg(int _arg) { + Instruction child = getFirstChild(); + _arg++; + + while (_arg-- != 0) { + child = child.getNextExpr(); + } + + return (child); + } + + @Override public Instruction getInstanceReference() { + return (getFirstChild()); + } + + @Override public int getStackConsumeCount() { + return (getConstantPoolInterfaceMethodEntry().getStackConsumeCount() + 1); // + 1 to account for instance 'this' + + } + + @Override public int getStackProduceCount() { + return (getConstantPoolInterfaceMethodEntry().getStackProduceCount()); // + 1 to account for instance 'this' + } + } + + public static class I_INVOKEDYNAMIC extends Index16 implements InterfaceConstantPoolMethodIndexAccessor{ + private final int args; + + public I_INVOKEDYNAMIC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.INVOKEDYNAMIC, _byteReader, _wide); + args = _byteReader.u1(); + @SuppressWarnings("unused") final int zeroByte = _byteReader.u1(); + + } + + @Override public int getArgs() { + return (args); + } + + @Override public String getDescription() { + return ("pop args and call the invoke dynamic method referenced by 16 bit constant index"); + } + + @Override public int getConstantPoolInterfaceMethodIndex() { + return (index); + } + + @Override public ConstantPool.InterfaceMethodEntry getConstantPoolInterfaceMethodEntry() { + return (method.getConstantPool().getInterfaceMethodEntry(getConstantPoolInterfaceMethodIndex())); + } + + @Override public Instruction getArg(int _arg) { + Instruction child = getFirstChild(); + _arg++; + while (_arg-- != 0) { + child = child.getNextExpr(); + } + return (child); + } + + @Override public Instruction getInstanceReference() { + return (getFirstChild()); + } + + @Override public int getStackConsumeCount() { + return (getConstantPoolInterfaceMethodEntry().getStackConsumeCount() + 1); // + 1 to account for instance 'this' + + } + + @Override public int getStackProduceCount() { + return (getConstantPoolInterfaceMethodEntry().getStackProduceCount()); // + 1 to account for instance 'this' + } + } + + public static class I_INVOKESPECIAL extends Index16 implements VirtualMethodCall{ + + public I_INVOKESPECIAL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.INVOKESPECIAL, _byteReader, _wide); + + } + + @Override public String getDescription() { + return ("pop object reference and args and call the special method referenced by 16 bit constant index"); + } + + @Override public int getConstantPoolMethodIndex() { + return (index); + } + + @Override public ConstantPool.MethodEntry getConstantPoolMethodEntry() { + return (method.getConstantPool().getMethodEntry(getConstantPoolMethodIndex())); + } + + @Override public Instruction getArg(int _arg) { + Instruction child = getFirstChild(); + _arg++; + while (_arg-- != 0) { + child = child.getNextExpr(); + } + return (child); + } + + @Override public Instruction getInstanceReference() { + return (getFirstChild()); + } + + @Override public int getStackConsumeCount() { + return (getConstantPoolMethodEntry().getStackConsumeCount() + 1); // + 1 to account for instance 'this' + + } + + @Override public int getStackProduceCount() { + return (getConstantPoolMethodEntry().getStackProduceCount()); + } + } + + public static class I_INVOKESTATIC extends Index16 implements MethodCall{ + + public I_INVOKESTATIC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.INVOKESTATIC, _byteReader, _wide); + + } + + @Override public String getDescription() { + return ("pop args and call the static method referenced by 16 bit constant index"); + } + + @Override public int getConstantPoolMethodIndex() { + return (index); + } + + @Override public ConstantPool.MethodEntry getConstantPoolMethodEntry() { + return (method.getConstantPool().getMethodEntry(getConstantPoolMethodIndex())); + } + + @Override public Instruction getArg(int _arg) { + Instruction child = getFirstChild(); + + while (_arg-- != 0) { + child = child.getNextExpr(); + } + + return (child); + } + + @Override public int getStackConsumeCount() { + return (getConstantPoolMethodEntry().getStackConsumeCount()); + } + + @Override public int getStackProduceCount() { + return (getConstantPoolMethodEntry().getStackProduceCount()); + } + } + + public static class I_INVOKEVIRTUAL extends Index16 implements VirtualMethodCall{ + + public I_INVOKEVIRTUAL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.INVOKEVIRTUAL, _byteReader, _wide); + + } + + @Override public String getDescription() { + return ("pop object reference and args and call the method referenced by 16 bit constant index"); + } + + @Override public int getConstantPoolMethodIndex() { + return (index); + } + + @Override public ConstantPool.MethodEntry getConstantPoolMethodEntry() { + return (method.getConstantPool().getMethodEntry(getConstantPoolMethodIndex())); + } + + @Override public Instruction getArg(int _arg) { + Instruction child = getFirstChild(); + _arg++; + + while (_arg-- != 0) { + child = child.getNextExpr(); + } + + return (child); + } + + @Override public Instruction getInstanceReference() { + return (getFirstChild()); + } + + @Override public int getStackConsumeCount() { + return (getConstantPoolMethodEntry().getStackConsumeCount() + 1); // + 1 to account for instance 'this' + } + + @Override public int getStackProduceCount() { + return (getConstantPoolMethodEntry().getStackProduceCount()); + } + } + + public static class I_IOR extends BinaryOperator{ + public I_IOR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IOR, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("or top two ints"); + } + } + + public static class I_IREM extends BinaryOperator{ + public I_IREM(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IREM, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("rem top two ints"); + } + } + + public static class I_IRETURN extends Return{ + public I_IRETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IRETURN, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("return popped int"); + } + } + + public static class I_ISHL extends BinaryOperator{ + public I_ISHL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ISHL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("shift left top int"); + } + } + + public static class I_ISHR extends BinaryOperator{ + public I_ISHR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ISHR, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("shift right top int"); + } + } + + public static class I_ISTORE extends LocalVariableIndex08Store{ + public I_ISTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ISTORE, _byteReader, _wide); + } + } + + public static class I_ISTORE_0 extends LocalVariableConstIndexStore{ + public I_ISTORE_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ISTORE_0, _byteReader, _wide, 0); + } + } + + public static class I_ISTORE_1 extends LocalVariableConstIndexStore{ + public I_ISTORE_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ISTORE_1, _byteReader, _wide, 1); + } + } + + public static class I_ISTORE_2 extends LocalVariableConstIndexStore{ + public I_ISTORE_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ISTORE_2, _byteReader, _wide, 2); + } + } + + public static class I_ISTORE_3 extends LocalVariableConstIndexStore{ + public I_ISTORE_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ISTORE_3, _byteReader, _wide, 3); + } + } + + public static class I_ISUB extends BinaryOperator{ + public I_ISUB(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.ISUB, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("sub top two ints"); + } + } + + public static class I_IUSHR extends BinaryOperator{ + public I_IUSHR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IUSHR, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("shift right top int unsigned"); + } + } + + public static class I_IXOR extends BinaryOperator{ + public I_IXOR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.IXOR, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("xor top two ints"); + } + } + + public static class I_JSR extends UnconditionalBranch16{ + public I_JSR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.JSR, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("jump to subroutine "); + } + } + + public static class I_JSR_W extends Branch32{ + public I_JSR_W(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.JSR_W, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("subroutine"); + } + } + + public static class I_L2D extends CastOperator{ + public I_L2D(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.L2D, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop long push double"); + } + } + + public static class I_L2F extends CastOperator{ + public I_L2F(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.L2F, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop long push float"); + } + } + + public static class I_L2I extends CastOperator{ + public I_L2I(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.L2I, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop long push int"); + } + } + + public static class I_LADD extends BinaryOperator{ + public I_LADD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LADD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("add top two longs"); + } + } + + public static class I_LALOAD extends AccessArrayElement{ + public I_LALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LALOAD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push long from arrayref and index"); + } + } + + public static class I_LAND extends BinaryOperator{ + public I_LAND(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LAND, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("and top two longs"); + } + } + + public static class I_LASTORE extends AssignToArrayElement{ + public I_LASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LASTORE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop long into arrayref[index]"); + } + } + + public static class I_LCMP extends BinaryOperator{ + public I_LCMP(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LCMP, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push result of long comparison"); + } + } + + public static class I_LCONST_0 extends BytecodeEncodedConstant<Long>{ + public I_LCONST_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LCONST_0, _byteReader, _wide, 0L); + } + + @Override public String getDescription() { + return ("push (long) 0"); + } + } + + public static class I_LCONST_1 extends BytecodeEncodedConstant<Long>{ + public I_LCONST_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LCONST_1, _byteReader, _wide, 1L); + } + + @Override public String getDescription() { + return ("push (long) 1"); + } + } + + public static class I_LDC extends Index08 implements ConstantPoolEntryConstant{ + public I_LDC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LDC, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push constant at 08 bit index"); + } + + @Override public Object getValue() { + return (method.getConstantPool().getConstantEntry(getConstantPoolIndex())); + + } + + @Override public int getConstantPoolIndex() { + return (index); + } + + @Override public Entry getConstantPoolEntry() { + return (method.getConstantPool().get(getConstantPoolIndex())); + } + } + + public static class I_LDC_W extends Index16 implements ConstantPoolEntryConstant{ + public I_LDC_W(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LDC_W, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push constant at 16 bit index"); + } + + @Override public int getConstantPoolIndex() { + return (index); + } + + @Override public Object getValue() { + return (method.getConstantPool().getConstantEntry(getConstantPoolIndex())); + + } + + @Override public Entry getConstantPoolEntry() { + return (method.getConstantPool().get(getConstantPoolIndex())); + } + } + + public static class I_LDC2_W extends Index16 implements ConstantPoolEntryConstant{ + public I_LDC2_W(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LDC2_W, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push long/double constant at 16 bit index"); + } + + @Override public int getConstantPoolIndex() { + return (index); + } + + @Override public Entry getConstantPoolEntry() { + return (method.getConstantPool().get(getConstantPoolIndex())); + } + + @Override public Object getValue() { + return (method.getConstantPool().getConstantEntry(getConstantPoolIndex())); + } + } + + public static class I_LDIV extends BinaryOperator{ + public I_LDIV(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LDIV, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("div top two longs"); + } + } + + public static class I_LLOAD extends LocalVariableIndex08Load{ + public I_LLOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LLOAD, _byteReader, _wide); + } + } + + public static class I_LLOAD_0 extends LocalVariableConstIndexLoad{ + public I_LLOAD_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LLOAD_0, _byteReader, _wide, 0); + } + } + + public static class I_LLOAD_1 extends LocalVariableConstIndexLoad{ + public I_LLOAD_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LLOAD_1, _byteReader, _wide, 1); + } + } + + public static class I_LLOAD_2 extends LocalVariableConstIndexLoad{ + public I_LLOAD_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LLOAD_2, _byteReader, _wide, 2); + } + } + + public static class I_LLOAD_3 extends LocalVariableConstIndexLoad{ + public I_LLOAD_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LLOAD_3, _byteReader, _wide, 3); + } + } + + public static class I_LMUL extends BinaryOperator{ + public I_LMUL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LMUL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("mul top two longs"); + } + } + + public static class I_LNEG extends UnaryOperator{ + public I_LNEG(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LNEG, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("neg top long"); + } + } + + public static class I_LOOKUPSWITCH extends Switch{ + private final int[] matches; + + private final int npairs; + + public I_LOOKUPSWITCH(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LOOKUPSWITCH, _byteReader, _wide); + final int operandStart = _byteReader.getOffset(); + final int padLength = ((operandStart % 4) == 0) ? 0 : 4 - (operandStart % 4); + _byteReader.bytes(padLength); + offset = _byteReader.u4(); + npairs = _byteReader.u4(); + offsets = new int[npairs]; + matches = new int[npairs]; + for (int i = 0; i < npairs; i++) { + matches[i] = _byteReader.u4(); + offsets[i] = _byteReader.u4(); + } + } + + @Override public String getDescription() { + return ("help!"); + } + + public int[] getMatches() { + return (matches); + } + + public int getNpairs() { + return (npairs); + } + } + + public static class I_LOR extends BinaryOperator{ + public I_LOR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LOR, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("or top two longs"); + } + } + + public static class I_LREM extends BinaryOperator{ + public I_LREM(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LREM, _byteReader, _wide); + + } + + @Override public String getDescription() { + return ("rem top two longs"); + } + } + + public static class I_LRETURN extends Return{ + public I_LRETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LRETURN, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("return popped long"); + } + } + + public static class I_LSHL extends BinaryOperator{ + public I_LSHL(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LSHL, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("shift left top long"); + } + } + + public static class I_LSHR extends BinaryOperator{ + public I_LSHR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LSHR, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("shift right top long"); + } + } + + public static class I_LSTORE extends LocalVariableIndex08Store{ + public I_LSTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LSTORE, _byteReader, _wide); + } + } + + public static class I_LSTORE_0 extends LocalVariableConstIndexStore{ + public I_LSTORE_0(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LSTORE_0, _byteReader, _wide, 0); + } + } + + public static class I_LSTORE_1 extends LocalVariableConstIndexStore{ + public I_LSTORE_1(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LSTORE_1, _byteReader, _wide, 1); + } + } + + public static class I_LSTORE_2 extends LocalVariableConstIndexStore{ + public I_LSTORE_2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LSTORE_2, _byteReader, _wide, 2); + } + } + + public static class I_LSTORE_3 extends LocalVariableConstIndexStore{ + public I_LSTORE_3(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LSTORE_3, _byteReader, _wide, 3); + } + } + + public static class I_LSUB extends BinaryOperator{ + public I_LSUB(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LSUB, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("sub top two longs"); + } + } + + public static class I_LUSHR extends BinaryOperator{ + public I_LUSHR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LUSHR, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("shift right top long unsigned"); + } + } + + public static class I_LXOR extends BinaryOperator{ + public I_LXOR(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.LXOR, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("xor top two longs"); + } + } + + public static class I_MONITORENTER extends Instruction{ + public I_MONITORENTER(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.MONITORENTER, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop reference and inc monitor"); + } + } + + public static class I_MONITOREXIT extends Instruction{ + public I_MONITOREXIT(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.MONITOREXIT, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop reference and dec monitor"); + } + } + + public static class I_MULTIANEWARRAY extends Index16 implements New{ + private final int dimensions; + + public I_MULTIANEWARRAY(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.MULTIANEWARRAY, _byteReader, _wide); + dimensions = _byteReader.u1(); + } + + @Override public String getDescription() { + return ("create a multi dimension array of refernce types "); + } + + public int getDimensions() { + return (dimensions); + } + } + + public static class I_NEW extends Index16 implements New{ + public I_NEW(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.NEW, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("new"); + } + } + + public static class I_NEWARRAY extends Instruction implements New{ + private final int type; + + public I_NEWARRAY(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.NEWARRAY, _byteReader, _wide); + type = _byteReader.u1(); + } + + @Override public String getDescription() { + return ("new array simple type"); + } + + public int getType() { + return (type); + } + } + + public static class I_NOP extends Instruction{ + public I_NOP(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.NOP, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("no op"); + } + } + + public static class I_POP extends Instruction{ + public I_POP(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.POP, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop one item"); + } + } + + public static class I_POP2 extends Instruction{ + public I_POP2(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.POP2, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop 2 items"); + } + } + + public static class I_PUTFIELD extends Index16 implements AssignToInstanceField{ + public I_PUTFIELD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.PUTFIELD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop stack value into field referenced by 16 bit constant index"); + } + + @Override public int getConstantPoolFieldIndex() { + return (index); + } + + @Override public FieldEntry getConstantPoolFieldEntry() { + return (method.getConstantPool().getFieldEntry(getConstantPoolFieldIndex())); + } + + @Override public int getStackConsumeCount() { + return (2); + } + + @Override public int getStackProduceCount() { + return (0); + } + + @Override public Instruction getInstance() { + return (getFirstChild()); + } + + @Override public Instruction getValueToAssign() { + return (getLastChild()); + } + } + + public static class I_PUTSTATIC extends Index16 implements AssignToField{ + public I_PUTSTATIC(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.PUTSTATIC, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop stack value into 16 bit constant index as field"); + } + + @Override public int getConstantPoolFieldIndex() { + return (index); + } + + @Override public FieldEntry getConstantPoolFieldEntry() { + return (method.getConstantPool().getFieldEntry(getConstantPoolFieldIndex())); + } + + @Override public int getStackConsumeCount() { + return (1); + } + + @Override public int getStackProduceCount() { + return (0); + } + + @Override public Instruction getValueToAssign() { + return (getLastChild()); + } + } + + public static class I_RET extends Index08 implements AssignToLocalVariable{ + public I_RET(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.RET, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("return to pc in local var index 08 bit"); + } + + @Override public LocalVariableInfo getLocalVariableInfo() { + return (method.getLocalVariableTableEntry().getVariable(getThisPC() + getLength(), getLocalVariableTableIndex())); + } + + @Override public boolean isDeclaration() { + return (method.getLocalVariableTableEntry().getVariable(getThisPC() + getLength(), getLocalVariableTableIndex()) + .getStart() == (getThisPC() + getLength())); + } + + @Override public int getLocalVariableTableIndex() { + return (index); + } + + // @Override Instruction getValue() { + // return (getFirstChild()); + //} + } + + public static class I_RETURN extends Return{ + public I_RETURN(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.RETURN, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("return void"); + } + } + + public static class I_SALOAD extends AccessArrayElement{ + public I_SALOAD(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.SALOAD, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("push short from arrayref and index"); + } + } + + public static class I_SASTORE extends AssignToArrayElement{ + public I_SASTORE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.SASTORE, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("pop short into arrayref[index]"); + } + } + + public static class I_SIPUSH extends ImmediateConstant<Integer>{ + public I_SIPUSH(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.SIPUSH, _byteReader, _wide); + value = _byteReader.u2(); + } + + @Override public String getDescription() { + return ("push (short)"); + } + } + + public static class I_SWAP extends Instruction{ + public I_SWAP(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.SWAP, _byteReader, _wide); + } + + @Override public String getDescription() { + return ("swap top 2 items"); + } + } + + public static class I_TABLESWITCH extends Switch{ + private final int high; + + private final int low; + + public I_TABLESWITCH(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.TABLESWITCH, _byteReader, _wide); + final int operandStart = _byteReader.getOffset(); + final int padLength = ((operandStart % 4) == 0) ? 0 : 4 - (operandStart % 4); + _byteReader.bytes(padLength); + offset = _byteReader.u4(); + low = _byteReader.u4(); + high = _byteReader.u4(); + offsets = new int[(high - low) + 1]; + for (int i = low; i <= high; i++) { + offsets[i - low] = _byteReader.u4(); + } + } + + @Override public String getDescription() { + return ("help!"); + } + + public int getHigh() { + return (high); + } + + public int getLow() { + return (low); + } + } + + public static class I_WIDE extends Instruction{ + private boolean iinc; + + private int increment; + + private final int index; + + private final int wideopcode; + + public I_WIDE(MethodModel _methodPoolEntry, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, ByteCode.WIDE, _byteReader, _wide); + wideopcode = _byteReader.u1(); + index = _byteReader.u2(); + if ((((wideopcode >= 0x15) && (wideopcode <= 0x19)) || ((wideopcode >= 0x36) && (wideopcode <= 0x3a)) || (wideopcode == 0xa9))) { + iinc = false; + } else { + increment = _byteReader.u2(); + iinc = true; + } + } + + @Override public String getDescription() { + return ("help"); + } + + public int getIncrement() { + return (increment); + } + + public int getIndex() { + return (index); + } + + public int getWideopcode() { + return (wideopcode); + } + + public boolean isiinc() { + return (iinc); + } + } + + public static class I_END extends Instruction{ + public I_END(MethodModel method, int _pc) { + super(method, ByteCode.NONE, _pc); + } + + @Override public String getDescription() { + return ("END"); + } + } + + public static abstract class Index extends Instruction{ + protected int index; + + public Index(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + } + + public static abstract class IndexConst extends Index{ + public IndexConst(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide, int _index) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + index = _index; + } + } + + public static abstract class Index08 extends Index{ + public Index08(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + if (_wide) { + index = _byteReader.u2(); + } else { + index = _byteReader.u1(); + } + } + } + + public static abstract class Index16 extends Index{ + public Index16(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + index = _byteReader.u2(); + } + } + + public static abstract class Return extends Instruction{ + public Return(MethodModel _methodPoolEntry, ByteCode _byteCode, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _byteCode, _byteReader, _wide); + } + } + + public static abstract class Switch extends Branch{ + public Switch(MethodModel _methodPoolEntry, ByteCode _code, ByteReader _byteReader, boolean _wide) { + super(_methodPoolEntry, _code, _byteReader, _wide); + } + + protected int[] offsets; + + protected Instruction[] targets; + + public Instruction getTarget(int _index) { + return (targets[_index]); + } + + public void setTarget(int _index, Instruction _instruction) { + targets[_index] = _instruction; + } + + public int getAbsolute(int _index) { + return (getThisPC() + offsets[_index]); + } + + public int getOffset(int _index) { + return (offsets[_index]); + } + + public int[] getOffsets() { + return (offsets); + } + + public int getSize() { + return (offsets.length); + } + } + + public interface MethodCall{ + int getConstantPoolMethodIndex(); + + MethodEntry getConstantPoolMethodEntry(); + + Instruction getArg(int _arg); + } + + public interface VirtualMethodCall extends MethodCall{ + Instruction getInstanceReference(); + } + + public interface InterfaceConstantPoolMethodIndexAccessor{ + public int getConstantPoolInterfaceMethodIndex(); + + public ConstantPool.InterfaceMethodEntry getConstantPoolInterfaceMethodEntry(); + + public Instruction getInstanceReference(); + + public int getArgs(); + + public Instruction getArg(int _arg); + } + + public static interface New{ + } + + public interface FieldReference{ + public int getConstantPoolFieldIndex(); + + public FieldEntry getConstantPoolFieldEntry(); + } + + public interface AccessField extends FieldReference{ + + } + + public interface AssignToField extends FieldReference{ + Instruction getValueToAssign(); + } + + public interface AccessInstanceField extends AccessField{ + Instruction getInstance(); + } + + public interface AssignToInstanceField extends AssignToField{ + Instruction getInstance(); + } + + public interface LocalVariableTableIndexAccessor{ + int getLocalVariableTableIndex(); + + LocalVariableInfo getLocalVariableInfo(); + } + + public interface AccessLocalVariable extends LocalVariableTableIndexAccessor{ + + } + + public interface AssignToLocalVariable extends LocalVariableTableIndexAccessor{ + boolean isDeclaration(); + } + + public interface Constant<T> { + T getValue(); + } + + @SuppressWarnings("unchecked") public interface ConstantPoolEntryConstant extends Constant{ + int getConstantPoolIndex(); + + ConstantPool.Entry getConstantPoolEntry(); + }; + + public interface HasOperator{ + Operator getOperator(); + } + + public interface Binary extends HasOperator{ + Instruction getLhs(); + + Instruction getRhs(); + } + + public interface Unary extends HasOperator{ + Instruction getUnary(); + } + + public static class CloneInstruction extends Instruction{ + private final Instruction cloning; + + public CloneInstruction(MethodModel method, Instruction _cloning) { + super(method, ByteCode.CLONE, -1); + cloning = _cloning; + } + + @Override public String getDescription() { + return ("CLONE! " + getByteCode()); + } + + @Override public int getStackConsumeCount() { + return (cloning.getStackConsumeCount()); + } + + @Override public int getStackProduceCount() { + return (cloning.getStackProduceCount()); + } + + @Override public Instruction getReal() { + return (cloning); + } + } + + public static class IncrementInstruction extends Instruction{ + private final Instruction fieldOrVariable; + + private final boolean isInc; + + private final boolean isPre; + + public Instruction getFieldOrVariableReference() { + return fieldOrVariable; + } + + public boolean isPre() { + return isPre; + } + + public IncrementInstruction(MethodModel method, Instruction _fieldOrVariable, boolean _isInc, boolean _isPre) { + super(method, ByteCode.INCREMENT, -1); + + fieldOrVariable = _fieldOrVariable; + isPre = _isPre; + isInc = _isInc; + } + + @Override public String getDescription() { + return ("INCREMENT Local Variable! " + getByteCode()); + } + + public boolean isInc() { + return (isInc); + } + + @Override public Instruction getStartInstruction() { + return (fieldOrVariable.getStartInstruction()); + } + } + + public static class InlineAssignInstruction extends Instruction{ + private final AssignToLocalVariable assignToLocalVariable; + + private final Instruction rhs; + + public InlineAssignInstruction(MethodModel method, AssignToLocalVariable _assignToLocalVariable, Instruction _rhs) { + super(method, ByteCode.INLINE_ASSIGN, -1); + assignToLocalVariable = _assignToLocalVariable; + rhs = _rhs; + } + + @Override public String getDescription() { + return ("INLINE ASSIGN! " + getByteCode()); + } + + public AssignToLocalVariable getAssignToLocalVariable() { + return (assignToLocalVariable); + } + + public Instruction getRhs() { + return (rhs); + } + } + + public static class FieldArrayElementAssign extends Instruction{ + private final AssignToArrayElement assignToArrayElement; + + private final Instruction rhs; + + public FieldArrayElementAssign(MethodModel method, AssignToArrayElement _assignToArrayElement, Instruction _rhs) { + super(method, ByteCode.FIELD_ARRAY_ELEMENT_ASSIGN, -1); + assignToArrayElement = _assignToArrayElement; + rhs = _rhs; + } + + @Override public String getDescription() { + return ("FIELD ARRAY ELEMENT INCREMENT! " + getByteCode()); + } + + public AssignToArrayElement getAssignToArrayElement() { + return (assignToArrayElement); + } + + public Instruction getRhs() { + return (rhs); + } + } + + public static class FieldArrayElementIncrement extends Instruction{ + private final AssignToArrayElement assignToArrayElement; + + private final boolean isPre; + + private final boolean isInc; + + public FieldArrayElementIncrement(MethodModel method, AssignToArrayElement _assignToArrayElement, boolean _isInc, + boolean _isPre) { + super(method, ByteCode.FIELD_ARRAY_ELEMENT_INCREMENT, -1); + assignToArrayElement = _assignToArrayElement; + isPre = _isPre; + isInc = _isInc; + } + + @Override public String getDescription() { + return ("FIELD ARRAY ELEMENT INCREMENT! " + getByteCode()); + } + + public AssignToArrayElement getAssignToArrayElement() { + return (assignToArrayElement); + } + + public boolean isPre() { + return (isPre); + } + + public boolean isInc() { + return (isInc); + } + } + + public static class MultiAssignInstruction extends Instruction{ + private final Instruction from, to, common; + + public MultiAssignInstruction(MethodModel method, Instruction _common, Instruction _from, Instruction _to) { + super(method, ByteCode.MULTI_ASSIGN, -1); + common = _common; + from = _from; + to = _to; + } + + @Override public String getDescription() { + return ("MULTIASSIGN! " + getByteCode()); + } + + public Instruction getTo() { + return (to); + } + + public Instruction getFrom() { + return (from); + } + + public Instruction getCommon() { + return (common); + } + } + + public static class FakeGoto extends UnconditionalBranch{ + + public FakeGoto(MethodModel _methodPoolEntry, Instruction _target) { + super(_methodPoolEntry, ByteCode.FAKEGOTO, _target); + } + + @Override public String getDescription() { + return "FAKE goto"; + } + } +} diff --git a/src/main/java/com/aparapi/internal/instruction/InstructionTransformer.java b/src/main/java/com/aparapi/internal/instruction/InstructionTransformer.java index b930c37dc67ed554948e9362810154a8a112fd99..b6d359935458893fd81340d5661fd9d08f1b6651 100644 --- a/src/main/java/com/aparapi/internal/instruction/InstructionTransformer.java +++ b/src/main/java/com/aparapi/internal/instruction/InstructionTransformer.java @@ -1,68 +1,68 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.instruction; - -public abstract class InstructionTransformer{ - - private final String description; - - public abstract Instruction transform(final ExpressionList _expressionList, final Instruction i); - - public InstructionTransformer(String _description) { - description = _description; - } - - public String getDescription() { - return (description); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.instruction; + +public abstract class InstructionTransformer{ + + private final String description; + + public abstract Instruction transform(final ExpressionList _expressionList, final Instruction i); + + public InstructionTransformer(String _description) { + description = _description; + } + + public String getDescription() { + return (description); + } +} diff --git a/src/main/java/com/aparapi/internal/jni/OpenCLJNI.java b/src/main/java/com/aparapi/internal/jni/OpenCLJNI.java index 189b5358900161a4f30c5da8f1db683a592f6ff0..1d1562757c7c6861eccefbb20f91a59246d8095b 100644 --- a/src/main/java/com/aparapi/internal/jni/OpenCLJNI.java +++ b/src/main/java/com/aparapi/internal/jni/OpenCLJNI.java @@ -1,57 +1,57 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.jni; - -import com.aparapi.ProfileInfo; -import java.util.List; - -import com.aparapi.device.OpenCLDevice; -import com.aparapi.internal.opencl.OpenCLArgDescriptor; -import com.aparapi.internal.opencl.OpenCLKernel; -import com.aparapi.internal.opencl.OpenCLMem; -import com.aparapi.internal.opencl.OpenCLPlatform; -import com.aparapi.internal.opencl.OpenCLProgram; - -/** - * This class is intended to be used as a 'proxy' or 'facade' object for Java code to interact with JNI - */ -public abstract class OpenCLJNI{ - - protected native List<OpenCLPlatform> getPlatforms(); - - public OpenCLProgram createProgram(OpenCLDevice context, String openCLSource) - { - return this.createProgram(context, openCLSource, null); - } - - protected native OpenCLProgram createProgram(OpenCLDevice context, String openCLSource, String binaryKey); - - protected native OpenCLKernel createKernelJNI(OpenCLProgram program, String kernelName, OpenCLArgDescriptor[] args); - - protected native void invoke(OpenCLKernel openCLKernel, Object[] args); - - protected native void disposeKernel(OpenCLKernel openCLKernel); - - protected native void disposeProgram(OpenCLProgram openCLProgram); - - protected native List<ProfileInfo> getProfileInfo(OpenCLProgram openCLProgram); - - protected native void remap(OpenCLProgram program, OpenCLMem mem, long address); - - protected native byte[] getBytes(String className); - - protected native void getMem(OpenCLProgram program, OpenCLMem mem); -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.jni; + +import com.aparapi.ProfileInfo; +import java.util.List; + +import com.aparapi.device.OpenCLDevice; +import com.aparapi.internal.opencl.OpenCLArgDescriptor; +import com.aparapi.internal.opencl.OpenCLKernel; +import com.aparapi.internal.opencl.OpenCLMem; +import com.aparapi.internal.opencl.OpenCLPlatform; +import com.aparapi.internal.opencl.OpenCLProgram; + +/** + * This class is intended to be used as a 'proxy' or 'facade' object for Java code to interact with JNI + */ +public abstract class OpenCLJNI{ + + protected native List<OpenCLPlatform> getPlatforms(); + + public OpenCLProgram createProgram(OpenCLDevice context, String openCLSource) + { + return this.createProgram(context, openCLSource, null); + } + + protected native OpenCLProgram createProgram(OpenCLDevice context, String openCLSource, String binaryKey); + + protected native OpenCLKernel createKernelJNI(OpenCLProgram program, String kernelName, OpenCLArgDescriptor[] args); + + protected native void invoke(OpenCLKernel openCLKernel, Object[] args); + + protected native void disposeKernel(OpenCLKernel openCLKernel); + + protected native void disposeProgram(OpenCLProgram openCLProgram); + + protected native List<ProfileInfo> getProfileInfo(OpenCLProgram openCLProgram); + + protected native void remap(OpenCLProgram program, OpenCLMem mem, long address); + + protected native byte[] getBytes(String className); + + protected native void getMem(OpenCLProgram program, OpenCLMem mem); +} diff --git a/src/main/java/com/aparapi/internal/kernel/KernelArg.java b/src/main/java/com/aparapi/internal/kernel/KernelArg.java index d8c92ab7cc3f89bd2a320ecb6bb1e45db89227dd..4a7830ae52ff2234b614c27239e3b8ca80bda101 100644 --- a/src/main/java/com/aparapi/internal/kernel/KernelArg.java +++ b/src/main/java/com/aparapi/internal/kernel/KernelArg.java @@ -1,283 +1,283 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.kernel; - -import com.aparapi.internal.jni.*; -import com.aparapi.internal.model.*; -import com.aparapi.internal.util.*; - -import java.lang.reflect.*; -import java.nio.*; - -/** - * Each field (or captured field in the case of an anonymous inner class) referenced by any bytecode reachable from the users Kernel.run(), will - * need to be represented as a <code>KernelArg</code>. - * - * @see com.aparapi.Kernel#execute(int _globalSize) - * - * @author gfrost - * - */ -public class KernelArg extends KernelArgJNI{ - - /** - * The byte array for obj conversion passed to opencl - */ - private byte[] objArrayBuffer; - - /** - * The ByteBuffer fronting the byte array - */ - private ByteBuffer objArrayByteBuffer; - - /** - * ClassModel of the array elements (not used on JNI side) - * - */ - private ClassModel objArrayElementModel; - - /** - * Only set for AparapiBuffer objs, - */ - private Object primitiveBuf; - - /** - * Size of this primitive - */ - private int primitiveSize; - - /** - * Default constructor - */ - protected KernelArg() { - // empty - } - - /** - * @return the objArrayBuffer - */ - protected byte[] getObjArrayBuffer() { - return objArrayBuffer; - } - - /** - * @param objArrayBuffer the objArrayBuffer to set - */ - protected void setObjArrayBuffer(byte[] objArrayBuffer) { - this.objArrayBuffer = objArrayBuffer; - } - - /** - * @return the objArrayByteBuffer - */ - protected ByteBuffer getObjArrayByteBuffer() { - return objArrayByteBuffer; - } - - /** - * @param objArrayByteBuffer the objArrayByteBuffer to set - */ - protected void setObjArrayByteBuffer(ByteBuffer objArrayByteBuffer) { - this.objArrayByteBuffer = objArrayByteBuffer; - } - - /** - * @return the objArrayElementModel - */ - protected ClassModel getObjArrayElementModel() { - return objArrayElementModel; - } - - /** - * @param objArrayElementModel the objArrayElementModel to set - */ - protected void setObjArrayElementModel(ClassModel objArrayElementModel) { - this.objArrayElementModel = objArrayElementModel; - } - - /** - * @return the primitiveBuf - */ - protected Object getPrimitiveBuf() { - return primitiveBuf; - } - - /** - * @param primitiveBuf the primitiveBuf to set - */ - protected void setPrimitiveBuf(Object primitiveBuf) { - this.primitiveBuf = primitiveBuf; - } - - /** - * @return the primitiveSize - */ - protected int getPrimitiveSize() { - return primitiveSize; - } - - /** - * @param primitiveSize the primitiveSize to set - */ - protected void setPrimitiveSize(int primitiveSize) { - this.primitiveSize = primitiveSize; - } - - /** - * @return the type - */ - protected int getType() { - return type; - } - - /** - * @param type the type to set - */ - protected void setType(int type) { - this.type = type; - } - - /** - * @return the name - */ - protected String getName() { - return name; - } - - /** - * @param name the name to set - */ - protected void setName(String name) { - this.name = name; - } - - /** - * @return the javaArray - */ - protected Object getJavaArray() { - return javaArray; - } - - /** - * @param javaArray the javaArray to set - */ - protected void setJavaArray(Object javaArray) { - this.javaArray = javaArray; - } - - /** - * @return the sizeInBytes - */ - protected int getSizeInBytes() { - return sizeInBytes; - } - - /** - * @param sizeInBytes the sizeInBytes to set - */ - protected void setSizeInBytes(int sizeInBytes) { - this.sizeInBytes = sizeInBytes; - } - - /** - * @return the numElements - */ - protected int getNumElements() { - return numElements; - } - - /** - * @param numElements the numElements to set - */ - protected void setNumElements(int numElements) { - this.numElements = numElements; - } - - /** - * @return the array - */ - protected Object getArray() { - return array; - } - - /** - * @param array the array to set - */ - protected void setArray(Object array) { - this.array = array; - } - - /** - * @return the field - */ - protected Field getField() { - return field; - } - - /** - * @param field the field to set - */ - protected void setField(Field field) { - this.field = field; - } - - /** - * @return the buffer - */ - protected Object getJavaBuffer() { - return javaBuffer; - } - - /** - * @param buffer the buffer to set - */ - protected void setJavaBuffer(Object buffer) { - this.javaBuffer = buffer; - } - - /** - * @return the number of dimensions to buffer - */ - protected int getNumDims() { - return numDims; - } - - /** - * @param numDims the number of dimensions for the buffer - */ - protected void setNumDims(int numDims) { - this.numDims = numDims; - } - - /** - * @return the dimensions for the buffer - */ - protected int[] getDims() { - return dims; - } - - /** - * @param dims the dimsensions for the buffer - */ - protected void setDims(int[] dims) { - this.dims = dims; - } - - @Override - public String toString() { - return Reflection.getSimpleName(field.getType()) + " " + field.getName(); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.kernel; + +import com.aparapi.internal.jni.*; +import com.aparapi.internal.model.*; +import com.aparapi.internal.util.*; + +import java.lang.reflect.*; +import java.nio.*; + +/** + * Each field (or captured field in the case of an anonymous inner class) referenced by any bytecode reachable from the users Kernel.run(), will + * need to be represented as a <code>KernelArg</code>. + * + * @see com.aparapi.Kernel#execute(int _globalSize) + * + * @author gfrost + * + */ +public class KernelArg extends KernelArgJNI{ + + /** + * The byte array for obj conversion passed to opencl + */ + private byte[] objArrayBuffer; + + /** + * The ByteBuffer fronting the byte array + */ + private ByteBuffer objArrayByteBuffer; + + /** + * ClassModel of the array elements (not used on JNI side) + * + */ + private ClassModel objArrayElementModel; + + /** + * Only set for AparapiBuffer objs, + */ + private Object primitiveBuf; + + /** + * Size of this primitive + */ + private int primitiveSize; + + /** + * Default constructor + */ + protected KernelArg() { + // empty + } + + /** + * @return the objArrayBuffer + */ + protected byte[] getObjArrayBuffer() { + return objArrayBuffer; + } + + /** + * @param objArrayBuffer the objArrayBuffer to set + */ + protected void setObjArrayBuffer(byte[] objArrayBuffer) { + this.objArrayBuffer = objArrayBuffer; + } + + /** + * @return the objArrayByteBuffer + */ + protected ByteBuffer getObjArrayByteBuffer() { + return objArrayByteBuffer; + } + + /** + * @param objArrayByteBuffer the objArrayByteBuffer to set + */ + protected void setObjArrayByteBuffer(ByteBuffer objArrayByteBuffer) { + this.objArrayByteBuffer = objArrayByteBuffer; + } + + /** + * @return the objArrayElementModel + */ + protected ClassModel getObjArrayElementModel() { + return objArrayElementModel; + } + + /** + * @param objArrayElementModel the objArrayElementModel to set + */ + protected void setObjArrayElementModel(ClassModel objArrayElementModel) { + this.objArrayElementModel = objArrayElementModel; + } + + /** + * @return the primitiveBuf + */ + protected Object getPrimitiveBuf() { + return primitiveBuf; + } + + /** + * @param primitiveBuf the primitiveBuf to set + */ + protected void setPrimitiveBuf(Object primitiveBuf) { + this.primitiveBuf = primitiveBuf; + } + + /** + * @return the primitiveSize + */ + protected int getPrimitiveSize() { + return primitiveSize; + } + + /** + * @param primitiveSize the primitiveSize to set + */ + protected void setPrimitiveSize(int primitiveSize) { + this.primitiveSize = primitiveSize; + } + + /** + * @return the type + */ + protected int getType() { + return type; + } + + /** + * @param type the type to set + */ + protected void setType(int type) { + this.type = type; + } + + /** + * @return the name + */ + protected String getName() { + return name; + } + + /** + * @param name the name to set + */ + protected void setName(String name) { + this.name = name; + } + + /** + * @return the javaArray + */ + protected Object getJavaArray() { + return javaArray; + } + + /** + * @param javaArray the javaArray to set + */ + protected void setJavaArray(Object javaArray) { + this.javaArray = javaArray; + } + + /** + * @return the sizeInBytes + */ + protected int getSizeInBytes() { + return sizeInBytes; + } + + /** + * @param sizeInBytes the sizeInBytes to set + */ + protected void setSizeInBytes(int sizeInBytes) { + this.sizeInBytes = sizeInBytes; + } + + /** + * @return the numElements + */ + protected int getNumElements() { + return numElements; + } + + /** + * @param numElements the numElements to set + */ + protected void setNumElements(int numElements) { + this.numElements = numElements; + } + + /** + * @return the array + */ + protected Object getArray() { + return array; + } + + /** + * @param array the array to set + */ + protected void setArray(Object array) { + this.array = array; + } + + /** + * @return the field + */ + protected Field getField() { + return field; + } + + /** + * @param field the field to set + */ + protected void setField(Field field) { + this.field = field; + } + + /** + * @return the buffer + */ + protected Object getJavaBuffer() { + return javaBuffer; + } + + /** + * @param buffer the buffer to set + */ + protected void setJavaBuffer(Object buffer) { + this.javaBuffer = buffer; + } + + /** + * @return the number of dimensions to buffer + */ + protected int getNumDims() { + return numDims; + } + + /** + * @param numDims the number of dimensions for the buffer + */ + protected void setNumDims(int numDims) { + this.numDims = numDims; + } + + /** + * @return the dimensions for the buffer + */ + protected int[] getDims() { + return dims; + } + + /** + * @param dims the dimsensions for the buffer + */ + protected void setDims(int[] dims) { + this.dims = dims; + } + + @Override + public String toString() { + return Reflection.getSimpleName(field.getType()) + " " + field.getName(); + } +} diff --git a/src/main/java/com/aparapi/internal/kernel/KernelDeviceProfile.java b/src/main/java/com/aparapi/internal/kernel/KernelDeviceProfile.java index b58dd6d20897e8877e6f162ea359d19dc438b6c8..c4ca0fb8785d6f25ca20b0f551aa48a938eda721 100644 --- a/src/main/java/com/aparapi/internal/kernel/KernelDeviceProfile.java +++ b/src/main/java/com/aparapi/internal/kernel/KernelDeviceProfile.java @@ -1,212 +1,212 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.kernel; - -import com.aparapi.*; -import com.aparapi.device.*; - -import java.text.*; -import java.util.*; -import java.util.logging.*; - -/** - * Created by Barney on 02/09/2015. - */ -public class KernelDeviceProfile { - - private static Logger logger = Logger.getLogger(Config.getLoggerName()); - private static final double MILLION = 1000 * 1000; - private static final int TABLE_COLUMN_HEADER_WIDTH = 21; - private static final int TABLE_COLUMN_COUNT_WIDTH = 8; - private static final int TABLE_COLUMN_WIDTH; - private static String tableHeader = null; - private final Class<? extends Kernel> kernel; - private final Device device; - private long[] currentTimes = new long[ProfilingEvent.values().length]; - private long[] accumulatedTimes = new long[ProfilingEvent.values().length]; - private ProfilingEvent lastEvent = null; - private final DecimalFormat format; - private long invocationCount = 0; - - static { - assert ProfilingEvent.START.ordinal() == 0 : "ProfilingEvent.START.ordinal() != 0"; - int max = 0; - for (ProfilingEvent event : ProfilingEvent.values()) { - max = Math.max(max, event.name().length()); - } - TABLE_COLUMN_WIDTH = max + 1; - } - - public KernelDeviceProfile(Class<? extends Kernel> kernel, Device device) { - this.kernel = kernel; - this.device = device; - this.format = (DecimalFormat) DecimalFormat.getNumberInstance(); - format.setMinimumFractionDigits(3); - format.setMaximumFractionDigits(3); - } - - public void onEvent(ProfilingEvent event) { - if (event == ProfilingEvent.START) { - if (lastEvent != null) { - logger.log(Level.SEVERE, "ProfilingEvent.START encountered without ProfilingEvent.EXECUTED"); - } else if (lastEvent == ProfilingEvent.START) { - logger.log(Level.SEVERE, "Duplicate event ProfilingEvent.START"); - } - Arrays.fill(currentTimes, 0L); - ++invocationCount; - } else { - if (lastEvent == null) { - if (event != ProfilingEvent.EXECUTED) { - logger.log(Level.SEVERE, "ProfilingEvent.START was not invoked prior to ProfilingEvent." + event); - } - } else { - for (int i = lastEvent.ordinal() + 1; i < event.ordinal(); ++i) { - currentTimes[i] = currentTimes[i - 1]; - } - } - } - currentTimes[event.ordinal()] = System.nanoTime(); - if (event == ProfilingEvent.EXECUTED) { - for (int i = 1; i < currentTimes.length; ++i) { - long elapsed = currentTimes[i] - currentTimes[i - 1]; - if (elapsed < 0) { - logger.log(Level.SEVERE, "negative elapsed time for event " + event); - break; - } - accumulatedTimes[i] += elapsed; - } - } - lastEvent = event; - if (event == ProfilingEvent.EXECUTED) { - lastEvent = null; - } - } - - /** Elapsed time for a single event only, i.e. since the previous stage rather than from the start. */ - public double getLastElapsedTime(ProfilingEvent stage) { - if (stage == ProfilingEvent.START) { - return 0; - } - return (currentTimes[stage.ordinal()] - currentTimes[stage.ordinal() - 1]) / MILLION; - } - - /** Elapsed time for all events {@code from} through {@code to}.*/ - public double getLastElapsedTime(ProfilingEvent from, ProfilingEvent to) { - return (currentTimes[to.ordinal()] - currentTimes[from.ordinal()]) / MILLION; - } - - /** Elapsed time for a single event only, i.e. since the previous stage rather than from the start, summed over all executions. */ - public double getCumulativeElapsedTime(ProfilingEvent stage) { - return (accumulatedTimes[stage.ordinal()]) / MILLION; - } - - /** Elapsed time of entire execution, summed over all executions. */ - public double getCumulativeElapsedTimeAll() { - double sum = 0; - for (int i = 1; i <= ProfilingEvent.EXECUTED.ordinal(); ++i) { - sum += accumulatedTimes[i]; - } - return sum; - } - - public static synchronized String getTableHeader() { - if (tableHeader == null) { - int length = ProfilingEvent.values().length; - StringBuilder builder = new StringBuilder(150); - appendRowHeaders(builder, "Device", "Count"); - for (int i = 1; i < length; ++i) { - ProfilingEvent stage = ProfilingEvent.values()[i]; - String heading = stage.name(); - appendCell(builder, heading); - } - builder.append(" ").append("Total"); - tableHeader = builder.toString(); - } - return tableHeader; - } - - public String getLastAsTableRow() { - double total = 0; - StringBuilder builder = new StringBuilder(150); - appendRowHeaders(builder, device.getShortDescription(), String.valueOf(invocationCount)); - for (int i = 1; i < currentTimes.length; ++i) { - ProfilingEvent stage = ProfilingEvent.values()[i]; - double time = getLastElapsedTime(stage); - total += time; - String formatted = format.format(time); - appendCell(builder, formatted); - } - builder.append(" ").append(format.format(total)); - return builder.toString(); - } - - public String getCumulativeAsTableRow() { - return internalCumulativeAsTableRow(false); - } - - public String getAverageAsTableRow() { - return internalCumulativeAsTableRow(true); - } - - private String internalCumulativeAsTableRow(boolean mean) { - double total = 0; - double count = mean ? invocationCount : 1; - StringBuilder builder = new StringBuilder(150); - appendRowHeaders(builder, device.getShortDescription(), String.valueOf(invocationCount)); - for (int i = 1; i < currentTimes.length; ++i) { - ProfilingEvent stage = ProfilingEvent.values()[i]; - double time = getCumulativeElapsedTime(stage); - if (mean) { - time /= count; - } - total += time; - String formatted = format.format(time); - appendCell(builder, formatted); - } - builder.append(" ").append(format.format(total)); - return builder.toString(); - } - - private static void appendRowHeaders(StringBuilder builder, String device, String count) { - if (device.length() > TABLE_COLUMN_HEADER_WIDTH - 1) { - device = device.substring(0, TABLE_COLUMN_HEADER_WIDTH - 1); - } - builder.append(device); - int padding = TABLE_COLUMN_HEADER_WIDTH - device.length(); - for (int i = 0; i < padding; ++i) { - builder.append(' '); - } - - builder.append(count); - padding = TABLE_COLUMN_COUNT_WIDTH - count.length(); - for (int i = 0; i < padding; ++i) { - builder.append(' '); - } - } - - private static void appendCell(StringBuilder builder, String cell) { - int padding = TABLE_COLUMN_WIDTH - cell.length(); - for (int paddingIndex = 0; paddingIndex < padding; ++paddingIndex) { - builder.append(' '); - } - builder.append(cell); - } - - @Override - public String toString() { - return "KernelDeviceProfile{" + kernel.toString() + ", " + device.getShortDescription() + "}"; - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.kernel; + +import com.aparapi.*; +import com.aparapi.device.*; + +import java.text.*; +import java.util.*; +import java.util.logging.*; + +/** + * Created by Barney on 02/09/2015. + */ +public class KernelDeviceProfile { + + private static Logger logger = Logger.getLogger(Config.getLoggerName()); + private static final double MILLION = 1000 * 1000; + private static final int TABLE_COLUMN_HEADER_WIDTH = 21; + private static final int TABLE_COLUMN_COUNT_WIDTH = 8; + private static final int TABLE_COLUMN_WIDTH; + private static String tableHeader = null; + private final Class<? extends Kernel> kernel; + private final Device device; + private long[] currentTimes = new long[ProfilingEvent.values().length]; + private long[] accumulatedTimes = new long[ProfilingEvent.values().length]; + private ProfilingEvent lastEvent = null; + private final DecimalFormat format; + private long invocationCount = 0; + + static { + assert ProfilingEvent.START.ordinal() == 0 : "ProfilingEvent.START.ordinal() != 0"; + int max = 0; + for (ProfilingEvent event : ProfilingEvent.values()) { + max = Math.max(max, event.name().length()); + } + TABLE_COLUMN_WIDTH = max + 1; + } + + public KernelDeviceProfile(Class<? extends Kernel> kernel, Device device) { + this.kernel = kernel; + this.device = device; + this.format = (DecimalFormat) DecimalFormat.getNumberInstance(); + format.setMinimumFractionDigits(3); + format.setMaximumFractionDigits(3); + } + + public void onEvent(ProfilingEvent event) { + if (event == ProfilingEvent.START) { + if (lastEvent != null) { + logger.log(Level.SEVERE, "ProfilingEvent.START encountered without ProfilingEvent.EXECUTED"); + } else if (lastEvent == ProfilingEvent.START) { + logger.log(Level.SEVERE, "Duplicate event ProfilingEvent.START"); + } + Arrays.fill(currentTimes, 0L); + ++invocationCount; + } else { + if (lastEvent == null) { + if (event != ProfilingEvent.EXECUTED) { + logger.log(Level.SEVERE, "ProfilingEvent.START was not invoked prior to ProfilingEvent." + event); + } + } else { + for (int i = lastEvent.ordinal() + 1; i < event.ordinal(); ++i) { + currentTimes[i] = currentTimes[i - 1]; + } + } + } + currentTimes[event.ordinal()] = System.nanoTime(); + if (event == ProfilingEvent.EXECUTED) { + for (int i = 1; i < currentTimes.length; ++i) { + long elapsed = currentTimes[i] - currentTimes[i - 1]; + if (elapsed < 0) { + logger.log(Level.SEVERE, "negative elapsed time for event " + event); + break; + } + accumulatedTimes[i] += elapsed; + } + } + lastEvent = event; + if (event == ProfilingEvent.EXECUTED) { + lastEvent = null; + } + } + + /** Elapsed time for a single event only, i.e. since the previous stage rather than from the start. */ + public double getLastElapsedTime(ProfilingEvent stage) { + if (stage == ProfilingEvent.START) { + return 0; + } + return (currentTimes[stage.ordinal()] - currentTimes[stage.ordinal() - 1]) / MILLION; + } + + /** Elapsed time for all events {@code from} through {@code to}.*/ + public double getLastElapsedTime(ProfilingEvent from, ProfilingEvent to) { + return (currentTimes[to.ordinal()] - currentTimes[from.ordinal()]) / MILLION; + } + + /** Elapsed time for a single event only, i.e. since the previous stage rather than from the start, summed over all executions. */ + public double getCumulativeElapsedTime(ProfilingEvent stage) { + return (accumulatedTimes[stage.ordinal()]) / MILLION; + } + + /** Elapsed time of entire execution, summed over all executions. */ + public double getCumulativeElapsedTimeAll() { + double sum = 0; + for (int i = 1; i <= ProfilingEvent.EXECUTED.ordinal(); ++i) { + sum += accumulatedTimes[i]; + } + return sum; + } + + public static synchronized String getTableHeader() { + if (tableHeader == null) { + int length = ProfilingEvent.values().length; + StringBuilder builder = new StringBuilder(150); + appendRowHeaders(builder, "Device", "Count"); + for (int i = 1; i < length; ++i) { + ProfilingEvent stage = ProfilingEvent.values()[i]; + String heading = stage.name(); + appendCell(builder, heading); + } + builder.append(" ").append("Total"); + tableHeader = builder.toString(); + } + return tableHeader; + } + + public String getLastAsTableRow() { + double total = 0; + StringBuilder builder = new StringBuilder(150); + appendRowHeaders(builder, device.getShortDescription(), String.valueOf(invocationCount)); + for (int i = 1; i < currentTimes.length; ++i) { + ProfilingEvent stage = ProfilingEvent.values()[i]; + double time = getLastElapsedTime(stage); + total += time; + String formatted = format.format(time); + appendCell(builder, formatted); + } + builder.append(" ").append(format.format(total)); + return builder.toString(); + } + + public String getCumulativeAsTableRow() { + return internalCumulativeAsTableRow(false); + } + + public String getAverageAsTableRow() { + return internalCumulativeAsTableRow(true); + } + + private String internalCumulativeAsTableRow(boolean mean) { + double total = 0; + double count = mean ? invocationCount : 1; + StringBuilder builder = new StringBuilder(150); + appendRowHeaders(builder, device.getShortDescription(), String.valueOf(invocationCount)); + for (int i = 1; i < currentTimes.length; ++i) { + ProfilingEvent stage = ProfilingEvent.values()[i]; + double time = getCumulativeElapsedTime(stage); + if (mean) { + time /= count; + } + total += time; + String formatted = format.format(time); + appendCell(builder, formatted); + } + builder.append(" ").append(format.format(total)); + return builder.toString(); + } + + private static void appendRowHeaders(StringBuilder builder, String device, String count) { + if (device.length() > TABLE_COLUMN_HEADER_WIDTH - 1) { + device = device.substring(0, TABLE_COLUMN_HEADER_WIDTH - 1); + } + builder.append(device); + int padding = TABLE_COLUMN_HEADER_WIDTH - device.length(); + for (int i = 0; i < padding; ++i) { + builder.append(' '); + } + + builder.append(count); + padding = TABLE_COLUMN_COUNT_WIDTH - count.length(); + for (int i = 0; i < padding; ++i) { + builder.append(' '); + } + } + + private static void appendCell(StringBuilder builder, String cell) { + int padding = TABLE_COLUMN_WIDTH - cell.length(); + for (int paddingIndex = 0; paddingIndex < padding; ++paddingIndex) { + builder.append(' '); + } + builder.append(cell); + } + + @Override + public String toString() { + return "KernelDeviceProfile{" + kernel.toString() + ", " + device.getShortDescription() + "}"; + } +} diff --git a/src/main/java/com/aparapi/internal/kernel/KernelManager.java b/src/main/java/com/aparapi/internal/kernel/KernelManager.java index 3ae9d30760c0bcd66dd7102bebefa19c149e4826..9bdce715dd9f0684ca3538e1ab6040f55c44194f 100644 --- a/src/main/java/com/aparapi/internal/kernel/KernelManager.java +++ b/src/main/java/com/aparapi/internal/kernel/KernelManager.java @@ -1,332 +1,332 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.kernel; - -import java.lang.reflect.Constructor; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; - -import com.aparapi.Config; -import com.aparapi.Kernel; -import com.aparapi.device.Device; -import com.aparapi.device.JavaDevice; -import com.aparapi.device.OpenCLDevice; -import com.aparapi.internal.util.Reflection; - -/** - * Created by Barney on 24/08/2015. - */ -public class KernelManager { - - private static KernelManager INSTANCE = new KernelManager(); - private LinkedHashMap<Integer, PreferencesWrapper> preferences = new LinkedHashMap<>(); - private LinkedHashMap<Class<? extends Kernel>, KernelProfile> profiles = new LinkedHashMap<>(); - private LinkedHashMap<Class<? extends Kernel>, Kernel> sharedInstances = new LinkedHashMap<>(); - - private KernelPreferences defaultPreferences; - - protected KernelManager() { - defaultPreferences = createDefaultPreferences(); - } - - public static KernelManager instance() { - return INSTANCE; - } - - public static void setKernelManager(KernelManager manager) { - INSTANCE = manager; - } - - static { - if (Config.dumpProfilesOnExit) { - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - StringBuilder builder = new StringBuilder(2048); - instance().reportProfilingSummary(builder); - System.out.println(builder); - } - }); - } - } - - /** This method returns a shared instance of a given Kernel subclass. The kernelClass needs a no-args constructor, which - * need not be public. - * - * <p>Each new Kernel instance requires a new JNIContext, the creation of which is expensive. There is apparently no simple solution by which a cached JNIContext can be reused - * for all instances of a given Kernel class, since it is intimately connected with resource aquisition and release. In the absence of a context caching solution, it is often - * highly desirable to only ever create one instance of any given Kernel subclass, which this method facilitates.</p> - * - * <p>In order to maintain thread saftey when using a shared instance, it is necessary to synchronize on the returned kernel for the duration of the process of setting up, - * executing and extracting the results from that kernel.</p> - * - * <p>This method instantiates a Kernel (per Kernel class) via Reflection, and thus can only be used where the Kernel class has a no-args constructor, which need not be public. - * In fact, if a Kernel subclass is designed to be used in conjunction with this method, it is recommended that its <b>only</b> constructor is a <b>private</b> no-args constructor. - * </p> - * - * @throws RuntimeException if the class cannot be instantiated - */ - public static <T extends Kernel> T sharedKernelInstance(Class<T> kernelClass) { - return instance().getSharedKernelInstance(kernelClass); - } - - /** Append a report to {@code builder} which contains information, per Kernel subclass, on which device is currently being used for the - * kernel class, and which (if any) devices failed to execute a given Kernel. - */ - public void reportDeviceUsage(StringBuilder builder, boolean withProfilingInfo) { - builder.append("Device Usage by Kernel Subclass"); - if (withProfilingInfo) { - builder.append(" (showing mean elapsed times in milliseconds)"); - } - builder.append("\n\n"); - for (PreferencesWrapper wrapper : preferences.values()) { - KernelPreferences preferences = wrapper.getPreferences(); - Class<? extends Kernel> klass = wrapper.getKernelClass(); - KernelProfile profile = withProfilingInfo ? profiles.get(klass) : null; - builder.append(klass.getName()).append(":\n\tusing ").append(preferences.getPreferredDevice(null).getShortDescription()); - List<Device> failedDevices = preferences.getFailedDevices(); - if (failedDevices.size() > 0) { - builder.append(", failed devices = "); - for (int i = 0; i < failedDevices.size(); ++i) { - builder.append(failedDevices.get(i).getShortDescription()); - if (i < failedDevices.size() - 1) { - builder.append(" | "); - } - } - } - if (profile != null) { - builder.append("\n"); - int row = 0; - for (KernelDeviceProfile deviceProfile : profile.getDeviceProfiles()) { - if (row == 0) { - builder.append(deviceProfile.getTableHeader()).append("\n"); - } - builder.append(deviceProfile.getAverageAsTableRow()).append("\n"); - ++row; - } - } - builder.append("\n"); - } - } - - public void reportProfilingSummary(StringBuilder builder) { - builder.append("\nProfiles by Kernel Subclass (mean elapsed times in milliseconds)\n\n"); - builder.append(KernelDeviceProfile.getTableHeader()).append("\n"); - for (Class<? extends Kernel> kernelClass : profiles.keySet()) { - String simpleName = Reflection.getSimpleName(kernelClass); - String kernelName = "----------------- [[ " + simpleName + " ]] "; - builder.append(kernelName); - int dashes = 132 - kernelName.length(); - for (int i = 0; i < dashes; ++i) { - builder.append('-'); - } - builder.append("\n"); - KernelProfile kernelProfile = profiles.get(kernelClass); - for (KernelDeviceProfile deviceProfile : kernelProfile.getDeviceProfiles()) { - builder.append(deviceProfile.getAverageAsTableRow()).append("\n"); - } - } - } - - - public KernelPreferences getPreferences(Kernel kernel) { - synchronized (preferences) { - PreferencesWrapper wrapper = preferences.get(kernel.hashCode()); - KernelPreferences kernelPreferences; - if (wrapper == null) { - kernelPreferences = new KernelPreferences(this, kernel.getClass()); - preferences.put(kernel.hashCode(), new PreferencesWrapper(kernel.getClass(), kernelPreferences)); - }else{ - kernelPreferences = preferences.get(kernel.hashCode()).getPreferences(); - } - return kernelPreferences; - } - } - - public void setPreferredDevices(Kernel _kernel, LinkedHashSet<Device> _devices) { - KernelPreferences kernelPreferences = getPreferences(_kernel); - kernelPreferences.setPreferredDevices(_devices); - } - - public KernelPreferences getDefaultPreferences() { - return defaultPreferences; - } - - public void setDefaultPreferredDevices(LinkedHashSet<Device> _devices) { - defaultPreferences.setPreferredDevices(_devices); - } - - protected KernelPreferences createDefaultPreferences() { - KernelPreferences preferences = new KernelPreferences(this, null); - preferences.setPreferredDevices(createDefaultPreferredDevices()); - return preferences; - } - - private <T extends Kernel> T getSharedKernelInstance(Class<T> kernelClass) { - synchronized (sharedInstances) { - T shared = (T) sharedInstances.get(kernelClass); - if (shared == null) { - try { - Constructor<T> constructor = kernelClass.getConstructor(); - constructor.setAccessible(true); - shared = constructor.newInstance(); - sharedInstances.put(kernelClass, shared); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - return shared; - } - } - - protected LinkedHashSet<Device> createDefaultPreferredDevices() { - LinkedHashSet<Device> devices = new LinkedHashSet<>(); - - List<OpenCLDevice> accelerators = OpenCLDevice.listDevices(Device.TYPE.ACC); - List<OpenCLDevice> gpus = OpenCLDevice.listDevices(Device.TYPE.GPU); - List<OpenCLDevice> cpus = OpenCLDevice.listDevices(Device.TYPE.CPU); - - Collections.sort(accelerators, getDefaultAcceleratorComparator()); - Collections.sort(gpus, getDefaultGPUComparator()); - - List<Device.TYPE> preferredDeviceTypes = getPreferredDeviceTypes(); - - for (Device.TYPE type : preferredDeviceTypes) { - switch (type) { - case UNKNOWN: - throw new AssertionError("UNKNOWN device type not supported"); - case GPU: - devices.addAll(gpus); - break; - case CPU: - devices.addAll(cpus); - break; - case JTP: - devices.add(JavaDevice.THREAD_POOL); - break; - case SEQ: - devices.add(JavaDevice.SEQUENTIAL); - break; - case ACC: - devices.addAll(accelerators); - break; - case ALT: - devices.add(JavaDevice.ALTERNATIVE_ALGORITHM); - break; - } - } - - return devices; - } - - protected List<Device.TYPE> getPreferredDeviceTypes() { - return Arrays.asList(Device.TYPE.ACC, Device.TYPE.GPU, Device.TYPE.CPU, Device.TYPE.ALT, Device.TYPE.JTP); - } - - /** NB, returns -ve for the better device. */ - protected Comparator<OpenCLDevice> getDefaultAcceleratorComparator() { - return new Comparator<OpenCLDevice>() { - @Override - public int compare(OpenCLDevice left, OpenCLDevice right) { - return (right.getMaxComputeUnits() - left.getMaxComputeUnits()); - } - }; - } - - /** NB, returns -ve for the better device. */ - protected Comparator<OpenCLDevice> getDefaultGPUComparator() { - return new Comparator<OpenCLDevice>() { - @Override - public int compare(OpenCLDevice left, OpenCLDevice right) { - return selectLhs(left, right) ? -1 : 1; - } - }; - } - - public Device bestDevice() { - return getDefaultPreferences().getPreferredDevice(null); - } - - protected static boolean selectLhs(OpenCLDevice _deviceLhs, OpenCLDevice _deviceRhs) { - boolean nvidiaLhs = _deviceLhs.getOpenCLPlatform().getVendor().toLowerCase().contains("nvidia"); - boolean nvidiaRhs = _deviceRhs.getOpenCLPlatform().getVendor().toLowerCase().contains("nvidia"); - if (nvidiaLhs || nvidiaRhs) { - return selectLhsIfCUDA(_deviceLhs, _deviceRhs); - } - return _deviceLhs.getMaxComputeUnits() > _deviceRhs.getMaxComputeUnits(); - } - - /** NVidia/CUDA architecture reports maxComputeUnits in a completely different context, i.e. maxComputeUnits is not same as - * (is much less than) the number of OpenCL cores available. - * - * <p>Therefore when comparing an NVidia device we use different criteria.</p> - */ - protected static boolean selectLhsIfCUDA(OpenCLDevice _deviceLhs, OpenCLDevice _deviceRhs) { - if (_deviceLhs.getType() != _deviceRhs.getType()) { - return selectLhsByType(_deviceLhs.getType(), _deviceRhs.getType()); - } - return _deviceLhs.getMaxWorkGroupSize() == _deviceRhs.getMaxWorkGroupSize() - ? _deviceLhs.getGlobalMemSize() > _deviceRhs.getGlobalMemSize() - : _deviceLhs.getMaxWorkGroupSize() > _deviceRhs.getMaxWorkGroupSize(); - } - - private static boolean selectLhsByType(Device.TYPE lhs, Device.TYPE rhs) { - return lhs.rank < rhs.rank; - } - - public KernelProfile getProfile(Class<? extends Kernel> kernelClass) { - synchronized (profiles) { - KernelProfile profile = profiles.get(kernelClass); - if (profile == null) { - profile = new KernelProfile(kernelClass); - profiles.put(kernelClass, profile); - } - return profile; - } - } - - /** New home for deprecated methods of {@link Device}. */ - public static class DeprecatedMethods { - - @Deprecated - public static Device firstDevice(Device.TYPE _type) { - List<Device> devices = instance().getDefaultPreferences().getPreferredDevices(null); - for (Device device : devices) { - if(device.getType() == _type) { - return device; - } - } - return null; - } - - @SuppressWarnings("deprecation") - @Deprecated - public static Device bestGPU() { - return firstDevice(Device.TYPE.GPU); - } - - @SuppressWarnings("deprecation") - @Deprecated - public static Device bestACC() { - return firstDevice(Device.TYPE.ACC); - } - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.kernel; + +import java.lang.reflect.Constructor; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; + +import com.aparapi.Config; +import com.aparapi.Kernel; +import com.aparapi.device.Device; +import com.aparapi.device.JavaDevice; +import com.aparapi.device.OpenCLDevice; +import com.aparapi.internal.util.Reflection; + +/** + * Created by Barney on 24/08/2015. + */ +public class KernelManager { + + private static KernelManager INSTANCE = new KernelManager(); + private LinkedHashMap<Integer, PreferencesWrapper> preferences = new LinkedHashMap<>(); + private LinkedHashMap<Class<? extends Kernel>, KernelProfile> profiles = new LinkedHashMap<>(); + private LinkedHashMap<Class<? extends Kernel>, Kernel> sharedInstances = new LinkedHashMap<>(); + + private KernelPreferences defaultPreferences; + + protected KernelManager() { + defaultPreferences = createDefaultPreferences(); + } + + public static KernelManager instance() { + return INSTANCE; + } + + public static void setKernelManager(KernelManager manager) { + INSTANCE = manager; + } + + static { + if (Config.dumpProfilesOnExit) { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + StringBuilder builder = new StringBuilder(2048); + instance().reportProfilingSummary(builder); + System.out.println(builder); + } + }); + } + } + + /** This method returns a shared instance of a given Kernel subclass. The kernelClass needs a no-args constructor, which + * need not be public. + * + * <p>Each new Kernel instance requires a new JNIContext, the creation of which is expensive. There is apparently no simple solution by which a cached JNIContext can be reused + * for all instances of a given Kernel class, since it is intimately connected with resource aquisition and release. In the absence of a context caching solution, it is often + * highly desirable to only ever create one instance of any given Kernel subclass, which this method facilitates.</p> + * + * <p>In order to maintain thread saftey when using a shared instance, it is necessary to synchronize on the returned kernel for the duration of the process of setting up, + * executing and extracting the results from that kernel.</p> + * + * <p>This method instantiates a Kernel (per Kernel class) via Reflection, and thus can only be used where the Kernel class has a no-args constructor, which need not be public. + * In fact, if a Kernel subclass is designed to be used in conjunction with this method, it is recommended that its <b>only</b> constructor is a <b>private</b> no-args constructor. + * </p> + * + * @throws RuntimeException if the class cannot be instantiated + */ + public static <T extends Kernel> T sharedKernelInstance(Class<T> kernelClass) { + return instance().getSharedKernelInstance(kernelClass); + } + + /** Append a report to {@code builder} which contains information, per Kernel subclass, on which device is currently being used for the + * kernel class, and which (if any) devices failed to execute a given Kernel. + */ + public void reportDeviceUsage(StringBuilder builder, boolean withProfilingInfo) { + builder.append("Device Usage by Kernel Subclass"); + if (withProfilingInfo) { + builder.append(" (showing mean elapsed times in milliseconds)"); + } + builder.append("\n\n"); + for (PreferencesWrapper wrapper : preferences.values()) { + KernelPreferences preferences = wrapper.getPreferences(); + Class<? extends Kernel> klass = wrapper.getKernelClass(); + KernelProfile profile = withProfilingInfo ? profiles.get(klass) : null; + builder.append(klass.getName()).append(":\n\tusing ").append(preferences.getPreferredDevice(null).getShortDescription()); + List<Device> failedDevices = preferences.getFailedDevices(); + if (failedDevices.size() > 0) { + builder.append(", failed devices = "); + for (int i = 0; i < failedDevices.size(); ++i) { + builder.append(failedDevices.get(i).getShortDescription()); + if (i < failedDevices.size() - 1) { + builder.append(" | "); + } + } + } + if (profile != null) { + builder.append("\n"); + int row = 0; + for (KernelDeviceProfile deviceProfile : profile.getDeviceProfiles()) { + if (row == 0) { + builder.append(deviceProfile.getTableHeader()).append("\n"); + } + builder.append(deviceProfile.getAverageAsTableRow()).append("\n"); + ++row; + } + } + builder.append("\n"); + } + } + + public void reportProfilingSummary(StringBuilder builder) { + builder.append("\nProfiles by Kernel Subclass (mean elapsed times in milliseconds)\n\n"); + builder.append(KernelDeviceProfile.getTableHeader()).append("\n"); + for (Class<? extends Kernel> kernelClass : profiles.keySet()) { + String simpleName = Reflection.getSimpleName(kernelClass); + String kernelName = "----------------- [[ " + simpleName + " ]] "; + builder.append(kernelName); + int dashes = 132 - kernelName.length(); + for (int i = 0; i < dashes; ++i) { + builder.append('-'); + } + builder.append("\n"); + KernelProfile kernelProfile = profiles.get(kernelClass); + for (KernelDeviceProfile deviceProfile : kernelProfile.getDeviceProfiles()) { + builder.append(deviceProfile.getAverageAsTableRow()).append("\n"); + } + } + } + + + public KernelPreferences getPreferences(Kernel kernel) { + synchronized (preferences) { + PreferencesWrapper wrapper = preferences.get(kernel.hashCode()); + KernelPreferences kernelPreferences; + if (wrapper == null) { + kernelPreferences = new KernelPreferences(this, kernel.getClass()); + preferences.put(kernel.hashCode(), new PreferencesWrapper(kernel.getClass(), kernelPreferences)); + }else{ + kernelPreferences = preferences.get(kernel.hashCode()).getPreferences(); + } + return kernelPreferences; + } + } + + public void setPreferredDevices(Kernel _kernel, LinkedHashSet<Device> _devices) { + KernelPreferences kernelPreferences = getPreferences(_kernel); + kernelPreferences.setPreferredDevices(_devices); + } + + public KernelPreferences getDefaultPreferences() { + return defaultPreferences; + } + + public void setDefaultPreferredDevices(LinkedHashSet<Device> _devices) { + defaultPreferences.setPreferredDevices(_devices); + } + + protected KernelPreferences createDefaultPreferences() { + KernelPreferences preferences = new KernelPreferences(this, null); + preferences.setPreferredDevices(createDefaultPreferredDevices()); + return preferences; + } + + private <T extends Kernel> T getSharedKernelInstance(Class<T> kernelClass) { + synchronized (sharedInstances) { + T shared = (T) sharedInstances.get(kernelClass); + if (shared == null) { + try { + Constructor<T> constructor = kernelClass.getConstructor(); + constructor.setAccessible(true); + shared = constructor.newInstance(); + sharedInstances.put(kernelClass, shared); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + return shared; + } + } + + protected LinkedHashSet<Device> createDefaultPreferredDevices() { + LinkedHashSet<Device> devices = new LinkedHashSet<>(); + + List<OpenCLDevice> accelerators = OpenCLDevice.listDevices(Device.TYPE.ACC); + List<OpenCLDevice> gpus = OpenCLDevice.listDevices(Device.TYPE.GPU); + List<OpenCLDevice> cpus = OpenCLDevice.listDevices(Device.TYPE.CPU); + + Collections.sort(accelerators, getDefaultAcceleratorComparator()); + Collections.sort(gpus, getDefaultGPUComparator()); + + List<Device.TYPE> preferredDeviceTypes = getPreferredDeviceTypes(); + + for (Device.TYPE type : preferredDeviceTypes) { + switch (type) { + case UNKNOWN: + throw new AssertionError("UNKNOWN device type not supported"); + case GPU: + devices.addAll(gpus); + break; + case CPU: + devices.addAll(cpus); + break; + case JTP: + devices.add(JavaDevice.THREAD_POOL); + break; + case SEQ: + devices.add(JavaDevice.SEQUENTIAL); + break; + case ACC: + devices.addAll(accelerators); + break; + case ALT: + devices.add(JavaDevice.ALTERNATIVE_ALGORITHM); + break; + } + } + + return devices; + } + + protected List<Device.TYPE> getPreferredDeviceTypes() { + return Arrays.asList(Device.TYPE.ACC, Device.TYPE.GPU, Device.TYPE.CPU, Device.TYPE.ALT, Device.TYPE.JTP); + } + + /** NB, returns -ve for the better device. */ + protected Comparator<OpenCLDevice> getDefaultAcceleratorComparator() { + return new Comparator<OpenCLDevice>() { + @Override + public int compare(OpenCLDevice left, OpenCLDevice right) { + return (right.getMaxComputeUnits() - left.getMaxComputeUnits()); + } + }; + } + + /** NB, returns -ve for the better device. */ + protected Comparator<OpenCLDevice> getDefaultGPUComparator() { + return new Comparator<OpenCLDevice>() { + @Override + public int compare(OpenCLDevice left, OpenCLDevice right) { + return selectLhs(left, right) ? -1 : 1; + } + }; + } + + public Device bestDevice() { + return getDefaultPreferences().getPreferredDevice(null); + } + + protected static boolean selectLhs(OpenCLDevice _deviceLhs, OpenCLDevice _deviceRhs) { + boolean nvidiaLhs = _deviceLhs.getOpenCLPlatform().getVendor().toLowerCase().contains("nvidia"); + boolean nvidiaRhs = _deviceRhs.getOpenCLPlatform().getVendor().toLowerCase().contains("nvidia"); + if (nvidiaLhs || nvidiaRhs) { + return selectLhsIfCUDA(_deviceLhs, _deviceRhs); + } + return _deviceLhs.getMaxComputeUnits() > _deviceRhs.getMaxComputeUnits(); + } + + /** NVidia/CUDA architecture reports maxComputeUnits in a completely different context, i.e. maxComputeUnits is not same as + * (is much less than) the number of OpenCL cores available. + * + * <p>Therefore when comparing an NVidia device we use different criteria.</p> + */ + protected static boolean selectLhsIfCUDA(OpenCLDevice _deviceLhs, OpenCLDevice _deviceRhs) { + if (_deviceLhs.getType() != _deviceRhs.getType()) { + return selectLhsByType(_deviceLhs.getType(), _deviceRhs.getType()); + } + return _deviceLhs.getMaxWorkGroupSize() == _deviceRhs.getMaxWorkGroupSize() + ? _deviceLhs.getGlobalMemSize() > _deviceRhs.getGlobalMemSize() + : _deviceLhs.getMaxWorkGroupSize() > _deviceRhs.getMaxWorkGroupSize(); + } + + private static boolean selectLhsByType(Device.TYPE lhs, Device.TYPE rhs) { + return lhs.rank < rhs.rank; + } + + public KernelProfile getProfile(Class<? extends Kernel> kernelClass) { + synchronized (profiles) { + KernelProfile profile = profiles.get(kernelClass); + if (profile == null) { + profile = new KernelProfile(kernelClass); + profiles.put(kernelClass, profile); + } + return profile; + } + } + + /** New home for deprecated methods of {@link Device}. */ + public static class DeprecatedMethods { + + @Deprecated + public static Device firstDevice(Device.TYPE _type) { + List<Device> devices = instance().getDefaultPreferences().getPreferredDevices(null); + for (Device device : devices) { + if(device.getType() == _type) { + return device; + } + } + return null; + } + + @SuppressWarnings("deprecation") + @Deprecated + public static Device bestGPU() { + return firstDevice(Device.TYPE.GPU); + } + + @SuppressWarnings("deprecation") + @Deprecated + public static Device bestACC() { + return firstDevice(Device.TYPE.ACC); + } + } +} diff --git a/src/main/java/com/aparapi/internal/kernel/KernelManagers.java b/src/main/java/com/aparapi/internal/kernel/KernelManagers.java index d9767812ce42ed9632fc3debbe57f02179d52e14..6784f6d2122c1db5a930a8cba987abbbf92f7128 100644 --- a/src/main/java/com/aparapi/internal/kernel/KernelManagers.java +++ b/src/main/java/com/aparapi/internal/kernel/KernelManagers.java @@ -1,46 +1,46 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.kernel; - -import com.aparapi.device.*; - -import java.util.*; - -/** - * KernelManager instances useful for debugging. - */ -public class KernelManagers { - - public static final KernelManager JTP_ONLY = new KernelManager() { - - private List<Device.TYPE> types = Collections.singletonList(Device.TYPE.JTP); - - @Override - protected List<Device.TYPE> getPreferredDeviceTypes() { - return types; - } - }; - - public static final KernelManager SEQUENTIAL_ONLY = new KernelManager() { - - private final List<Device.TYPE> types = Collections.singletonList(Device.TYPE.SEQ); - - @Override - protected List<Device.TYPE> getPreferredDeviceTypes() { - return types; - } - }; -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.kernel; + +import com.aparapi.device.*; + +import java.util.*; + +/** + * KernelManager instances useful for debugging. + */ +public class KernelManagers { + + public static final KernelManager JTP_ONLY = new KernelManager() { + + private List<Device.TYPE> types = Collections.singletonList(Device.TYPE.JTP); + + @Override + protected List<Device.TYPE> getPreferredDeviceTypes() { + return types; + } + }; + + public static final KernelManager SEQUENTIAL_ONLY = new KernelManager() { + + private final List<Device.TYPE> types = Collections.singletonList(Device.TYPE.SEQ); + + @Override + protected List<Device.TYPE> getPreferredDeviceTypes() { + return types; + } + }; +} diff --git a/src/main/java/com/aparapi/internal/kernel/KernelProfile.java b/src/main/java/com/aparapi/internal/kernel/KernelProfile.java index b4d70681db1368c169fd4644778fbb78aa308a25..017ce761f665246661749397625f5a3280509fcd 100644 --- a/src/main/java/com/aparapi/internal/kernel/KernelProfile.java +++ b/src/main/java/com/aparapi/internal/kernel/KernelProfile.java @@ -1,121 +1,121 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.kernel; - -import com.aparapi.*; -import com.aparapi.device.*; - -import java.util.*; -import java.util.logging.*; - -/** - * Collects profiling information per kernel class per device. Not thread safe, it is necessary for client code to correctly synchronize on - * objects of this class. - */ -public class KernelProfile { - - private static final double MILLION = 1000000d; - private static Logger logger = Logger.getLogger(Config.getLoggerName()); - private final Class<? extends Kernel> kernelClass; - private LinkedHashMap<Device, KernelDeviceProfile> deviceProfiles = new LinkedHashMap<>(); - private Device currentDevice; - private Device lastDevice; - private KernelDeviceProfile currentDeviceProfile; - - public KernelProfile(Class<? extends Kernel> _kernelClass) { - kernelClass = _kernelClass; - } - - public double getLastExecutionTime() { - KernelDeviceProfile lastDeviceProfile = getLastDeviceProfile(); - return lastDeviceProfile == null ? Double.NaN : lastDeviceProfile.getLastElapsedTime(ProfilingEvent.START, ProfilingEvent.EXECUTED) / MILLION; - } - - public double getLastConversionTime() { - KernelDeviceProfile lastDeviceProfile = getLastDeviceProfile(); - return lastDeviceProfile == null ? Double.NaN : lastDeviceProfile.getLastElapsedTime(ProfilingEvent.START, ProfilingEvent.PREPARE_EXECUTE) / MILLION; - } - - public double getAccumulatedTotalTime() { - KernelDeviceProfile lastDeviceProfile = getLastDeviceProfile(); - if (lastDeviceProfile == null) { - return Double.NaN; - } - else { - return lastDeviceProfile.getCumulativeElapsedTimeAll() / MILLION; - } - } - - public KernelDeviceProfile getLastDeviceProfile() { - return deviceProfiles.get(currentDevice); - } - - void onStart(Device device) { - currentDevice = device; - synchronized (deviceProfiles) { - currentDeviceProfile = deviceProfiles.get(device); - if (currentDeviceProfile == null) { - currentDeviceProfile = new KernelDeviceProfile(kernelClass, device); - deviceProfiles.put(device, currentDeviceProfile); - } - } - currentDeviceProfile.onEvent(ProfilingEvent.START); - } - - void onEvent(ProfilingEvent event) { - switch (event) { - case CLASS_MODEL_BUILT: // fallthrough - case OPENCL_GENERATED: // fallthrough - case INIT_JNI: // fallthrough - case OPENCL_COMPILED: // fallthrough - case PREPARE_EXECUTE: // fallthrough - case EXECUTED: // fallthrough - { - if (currentDeviceProfile == null) { - logger.log(Level.SEVERE, "Error in KernelProfile, no currentDevice (synchronization error?"); - } - currentDeviceProfile.onEvent(event); - break; - } - case START: - throw new IllegalArgumentException("must use onStart(Device) to start profiling"); - default: - throw new IllegalArgumentException("Unhandled event " + event); - } - } - - void onFinishedExecution() { - reset(); - } - - private void reset() { - lastDevice = currentDevice; - currentDevice = null; - currentDeviceProfile = null; - } - - public Collection<Device> getDevices() { - return deviceProfiles.keySet(); - } - - public Collection<KernelDeviceProfile> getDeviceProfiles() { - return deviceProfiles.values(); - } - - public KernelDeviceProfile getDeviceProfile(Device device) { - return deviceProfiles.get(device); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.kernel; + +import com.aparapi.*; +import com.aparapi.device.*; + +import java.util.*; +import java.util.logging.*; + +/** + * Collects profiling information per kernel class per device. Not thread safe, it is necessary for client code to correctly synchronize on + * objects of this class. + */ +public class KernelProfile { + + private static final double MILLION = 1000000d; + private static Logger logger = Logger.getLogger(Config.getLoggerName()); + private final Class<? extends Kernel> kernelClass; + private LinkedHashMap<Device, KernelDeviceProfile> deviceProfiles = new LinkedHashMap<>(); + private Device currentDevice; + private Device lastDevice; + private KernelDeviceProfile currentDeviceProfile; + + public KernelProfile(Class<? extends Kernel> _kernelClass) { + kernelClass = _kernelClass; + } + + public double getLastExecutionTime() { + KernelDeviceProfile lastDeviceProfile = getLastDeviceProfile(); + return lastDeviceProfile == null ? Double.NaN : lastDeviceProfile.getLastElapsedTime(ProfilingEvent.START, ProfilingEvent.EXECUTED) / MILLION; + } + + public double getLastConversionTime() { + KernelDeviceProfile lastDeviceProfile = getLastDeviceProfile(); + return lastDeviceProfile == null ? Double.NaN : lastDeviceProfile.getLastElapsedTime(ProfilingEvent.START, ProfilingEvent.PREPARE_EXECUTE) / MILLION; + } + + public double getAccumulatedTotalTime() { + KernelDeviceProfile lastDeviceProfile = getLastDeviceProfile(); + if (lastDeviceProfile == null) { + return Double.NaN; + } + else { + return lastDeviceProfile.getCumulativeElapsedTimeAll() / MILLION; + } + } + + public KernelDeviceProfile getLastDeviceProfile() { + return deviceProfiles.get(currentDevice); + } + + void onStart(Device device) { + currentDevice = device; + synchronized (deviceProfiles) { + currentDeviceProfile = deviceProfiles.get(device); + if (currentDeviceProfile == null) { + currentDeviceProfile = new KernelDeviceProfile(kernelClass, device); + deviceProfiles.put(device, currentDeviceProfile); + } + } + currentDeviceProfile.onEvent(ProfilingEvent.START); + } + + void onEvent(ProfilingEvent event) { + switch (event) { + case CLASS_MODEL_BUILT: // fallthrough + case OPENCL_GENERATED: // fallthrough + case INIT_JNI: // fallthrough + case OPENCL_COMPILED: // fallthrough + case PREPARE_EXECUTE: // fallthrough + case EXECUTED: // fallthrough + { + if (currentDeviceProfile == null) { + logger.log(Level.SEVERE, "Error in KernelProfile, no currentDevice (synchronization error?"); + } + currentDeviceProfile.onEvent(event); + break; + } + case START: + throw new IllegalArgumentException("must use onStart(Device) to start profiling"); + default: + throw new IllegalArgumentException("Unhandled event " + event); + } + } + + void onFinishedExecution() { + reset(); + } + + private void reset() { + lastDevice = currentDevice; + currentDevice = null; + currentDeviceProfile = null; + } + + public Collection<Device> getDevices() { + return deviceProfiles.keySet(); + } + + public Collection<KernelDeviceProfile> getDeviceProfiles() { + return deviceProfiles.values(); + } + + public KernelDeviceProfile getDeviceProfile(Device device) { + return deviceProfiles.get(device); + } +} diff --git a/src/main/java/com/aparapi/internal/kernel/KernelRunner.java b/src/main/java/com/aparapi/internal/kernel/KernelRunner.java index 66d34cf6db5724e632d05e94e69ddf7ef513f31d..66f8e72b1bf269553a99494bb5043faeda228ff4 100644 --- a/src/main/java/com/aparapi/internal/kernel/KernelRunner.java +++ b/src/main/java/com/aparapi/internal/kernel/KernelRunner.java @@ -1,1790 +1,1790 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.kernel; - -import com.aparapi.*; -import com.aparapi.Kernel.Constant; -import com.aparapi.Kernel.*; -import com.aparapi.device.*; -import com.aparapi.internal.annotation.*; -import com.aparapi.internal.exception.*; -import com.aparapi.internal.instruction.InstructionSet.*; -import com.aparapi.internal.jni.*; -import com.aparapi.internal.model.*; -import com.aparapi.internal.util.*; -import com.aparapi.internal.writer.*; -import com.aparapi.opencl.*; - -import java.lang.reflect.*; -import java.nio.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.ForkJoinPool.*; -import java.util.logging.*; - -/** - * The class is responsible for executing <code>Kernel</code> implementations. <br/> - * - * The <code>KernelRunner</code> is the real workhorse for Aparapi. Each <code>Kernel</code> instance creates a single - * <code>KernelRunner</code> to encapsulate state and to help coordinate interactions between the <code>Kernel</code> - * and it's execution logic.<br/> - * - * The <code>KernelRunner</code> is created <i>lazily</i> as a result of calling <code>Kernel.execute()</code>. A this - * time the <code>ExecutionMode</code> is consulted to determine the default requested mode. This will dictate how - * the <code>KernelRunner</code> will attempt to execute the <code>Kernel</code> - * - * @see com.aparapi.Kernel#execute(int _globalSize) - * - * @author gfrost - * - */ -public class KernelRunner extends KernelRunnerJNI{ - - public static boolean BINARY_CACHING_DISABLED = false; - - private static final int MINIMUM_ARRAY_SIZE = 1; - - /** @see #getCurrentPass() */ - @UsedByJNICode public static final int PASS_ID_PREPARING_EXECUTION = -2; - /** @see #getCurrentPass() */ - @UsedByJNICode public static final int PASS_ID_COMPLETED_EXECUTION = -1; - @UsedByJNICode public static final int CANCEL_STATUS_FALSE = 0; - @UsedByJNICode public static final int CANCEL_STATUS_TRUE = 1; - private static final String CODE_GEN_ERROR_MARKER = CodeGenException.class.getName(); - - private static Logger logger = Logger.getLogger(Config.getLoggerName()); - - private long jniContextHandle = 0; - - private final Kernel kernel; - - private Entrypoint entryPoint; - - private int argc; - - // may be read by a thread other than the control thread, hence volatile - private volatile boolean executing; - - // may be read by a thread other than the control thread, hence volatile - private volatile int passId = PASS_ID_PREPARING_EXECUTION; - - /** - * A direct ByteBuffer used for asynchronous intercommunication between java and JNI C code. - * - * <p> - * At present this is a 4 byte buffer to be interpreted as an int[1], used for passing from java to C a single integer interpreted as a cancellation indicator. - */ - private final ByteBuffer inBufferRemote; - private final IntBuffer inBufferRemoteInt; - - /** A direct ByteBuffer used for asynchronous intercommunication between java and JNI C code. - * <p> - * At present this is a 4 byte buffer to be interpreted as an int[1], used for passing from C to java a single integer interpreted as a - * the current pass id. - */ - private final ByteBuffer outBufferRemote; - private final IntBuffer outBufferRemoteInt; - - private boolean isFallBack = false; // If isFallBack, rebuild the kernel (necessary?) - - private static final ForkJoinWorkerThreadFactory lowPriorityThreadFactory = new ForkJoinWorkerThreadFactory(){ - @Override public ForkJoinWorkerThread newThread(ForkJoinPool pool) { - ForkJoinWorkerThread newThread = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool); - newThread.setPriority(Thread.MIN_PRIORITY); - return newThread; - } - }; - - private static final ForkJoinPool threadPool = new ForkJoinPool(Runtime.getRuntime().availableProcessors(), - lowPriorityThreadFactory, null, false); - private static HashMap<Class<? extends Kernel>, String> openCLCache = new HashMap<>(); - private static LinkedHashSet<String> seenBinaryKeys = new LinkedHashSet<>(); - - /** - * Create a KernelRunner for a specific Kernel instance. - * - * @param _kernel - */ - public KernelRunner(Kernel _kernel) { - kernel = _kernel; - - inBufferRemote = ByteBuffer.allocateDirect(4); - outBufferRemote = ByteBuffer.allocateDirect(4); - - inBufferRemote.order(ByteOrder.nativeOrder()); - outBufferRemote.order(ByteOrder.nativeOrder()); - - inBufferRemoteInt = inBufferRemote.asIntBuffer(); - outBufferRemoteInt = outBufferRemote.asIntBuffer(); - - KernelManager.instance(); // ensures static initialization of KernelManager - } - - /** - * @see Kernel#cleanUpArrays(). - */ - public void cleanUpArrays() { - if (args != null && kernel.isRunningCL()) { - for (KernelArg arg : args) { - if ((arg.getType() & KernelRunnerJNI.ARG_ARRAY) != 0) { - Field field = arg.getField(); - if (field != null && field.getType().isArray() && !Modifier.isFinal(field.getModifiers())) { - field.setAccessible(true); - Class<?> componentType = field.getType().getComponentType(); - Object newValue = Array.newInstance(componentType, MINIMUM_ARRAY_SIZE); - try { - field.set(kernel, newValue); - } - catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - } - } - kernel.execute(0); - } else if (kernel.isRunningCL()) { - logger.log(Level.SEVERE, "KernelRunner#cleanUpArrays() could not execute as no args available (Kernel has not been executed?)"); - } - } - - /** - * <code>Kernel.dispose()</code> delegates to <code>KernelRunner.dispose()</code> which delegates to <code>disposeJNI()</code> to actually close JNI data structures.<br/> - * - * @see KernelRunnerJNI#disposeJNI(long) - */ - public synchronized void dispose() { - if (kernel.isRunningCL()) { - disposeJNI(jniContextHandle); - seenBinaryKeys.clear(); - } - // We are using a shared pool, so there's no need no shutdown it when kernel is disposed - // threadPool.shutdownNow(); - } - - private Set<String> capabilitiesSet; - - boolean hasFP64Support() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return (capabilitiesSet.contains(OpenCL.CL_KHR_FP64)); - } - - boolean hasSelectFPRoundingModeSupport() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_SELECT_FPROUNDING_MODE); - } - - boolean hasGlobalInt32BaseAtomicsSupport() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_GLOBAL_INT32_BASE_ATOMICS); - } - - boolean hasGlobalInt32ExtendedAtomicsSupport() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_GLOBAL_INT32_EXTENDED_ATOMICS); - } - - boolean hasLocalInt32BaseAtomicsSupport() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_LOCAL_INT32_BASE_ATOMICS); - } - - boolean hasLocalInt32ExtendedAtomicsSupport() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_LOCAL_INT32_EXTENDED_ATOMICS); - } - - boolean hasInt64BaseAtomicsSupport() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_INT64_BASE_ATOMICS); - } - - boolean hasInt64ExtendedAtomicsSupport() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_INT64_EXTENDED_ATOMICS); - } - - boolean has3DImageWritesSupport() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_3D_IMAGE_WRITES); - } - - boolean hasByteAddressableStoreSupport() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_BYTE_ADDRESSABLE_SUPPORT); - } - - boolean hasFP16Support() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_FP16); - } - - boolean hasGLSharingSupport() { - if (capabilitiesSet == null) { - throw new IllegalStateException("Capabilities queried before they were initialized"); - } - return capabilitiesSet.contains(OpenCL.CL_KHR_GL_SHARING); - } - - private static final class FJSafeCyclicBarrier extends CyclicBarrier{ - FJSafeCyclicBarrier(final int threads) { - super(threads); - } - - @Override public int await() throws InterruptedException, BrokenBarrierException { - class Awaiter implements ManagedBlocker{ - private int value; - - private boolean released; - - @Override public boolean block() throws InterruptedException { - try { - value = superAwait(); - released = true; - return true; - } catch (final BrokenBarrierException e) { - throw new RuntimeException(e); - } - } - - @Override public boolean isReleasable() { - return released; - } - - int getValue() { - return value; - } - } - final Awaiter awaiter = new Awaiter(); - ForkJoinPool.managedBlock(awaiter); - return awaiter.getValue(); - } - - int superAwait() throws InterruptedException, BrokenBarrierException { - return super.await(); - } - } - - // @FunctionalInterface - private interface ThreadIdSetter{ - void set(KernelState kernelState, int globalGroupId, int threadId); - } - - /** - * Execute using a Java thread pool, or sequentially, or using an alternative algorithm, usually as a result of failing to compile or execute OpenCL - */ - @SuppressWarnings("deprecation") - protected void executeJava(ExecutionSettings _settings, Device device) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("executeJava: range = " + _settings.range + ", device = " + device); - } - boolean legacySequentialMode = kernel.getExecutionMode().equals(Kernel.EXECUTION_MODE.SEQ); - - passId = PASS_ID_PREPARING_EXECUTION; - _settings.profile.onEvent(ProfilingEvent.PREPARE_EXECUTE); - - try { - if (device == JavaDevice.ALTERNATIVE_ALGORITHM) { - if (kernel.hasFallbackAlgorithm()) { - for (passId = 0; passId < _settings.passes; ++passId) { - kernel.executeFallbackAlgorithm(_settings.range, passId); - } - } else { - boolean silently = true; // not having an alternative algorithm is the normal state, and does not need reporting - fallBackToNextDevice(_settings, (Exception) null, silently); - } - } else { - final int localSize0 = _settings.range.getLocalSize(0); - final int localSize1 = _settings.range.getLocalSize(1); - final int localSize2 = _settings.range.getLocalSize(2); - final int globalSize1 = _settings.range.getGlobalSize(1); - if (legacySequentialMode || device == JavaDevice.SEQUENTIAL) { - /** - * SEQ mode is useful for testing trivial logic, but kernels which use SEQ mode cannot be used if the - * product of localSize(0..3) is >1. So we can use multi-dim ranges but only if the local size is 1 in all dimensions. - * - * As a result of this barrier is only ever 1 work item wide and probably should be turned into a no-op. - * - * So we need to check if the range is valid here. If not we have no choice but to punt. - */ - if ((localSize0 * localSize1 * localSize2) > 1) { - throw new IllegalStateException("Can't run range with group size >1 sequentially. Barriers would deadlock!"); - } - - final Kernel kernelClone = kernel.clone(); - final KernelState kernelState = kernelClone.getKernelState(); - - kernelState.setRange(_settings.range); - kernelState.setGroupId(0, 0); - kernelState.setGroupId(1, 0); - kernelState.setGroupId(2, 0); - kernelState.setLocalId(0, 0); - kernelState.setLocalId(1, 0); - kernelState.setLocalId(2, 0); - kernelState.setLocalBarrier(new FJSafeCyclicBarrier(1)); - - for (passId = 0; passId < _settings.passes; passId++) { - if (getCancelState() == CANCEL_STATUS_TRUE) { - break; - } - kernelState.setPassId(passId); - - if (_settings.range.getDims() == 1) { - for (int id = 0; id < _settings.range.getGlobalSize(0); id++) { - kernelState.setGlobalId(0, id); - kernelClone.run(); - } - } - else if (_settings.range.getDims() == 2) { - for (int x = 0; x < _settings.range.getGlobalSize(0); x++) { - kernelState.setGlobalId(0, x); - - for (int y = 0; y < globalSize1; y++) { - kernelState.setGlobalId(1, y); - kernelClone.run(); - } - } - } - else if (_settings.range.getDims() == 3) { - for (int x = 0; x < _settings.range.getGlobalSize(0); x++) { - kernelState.setGlobalId(0, x); - - for (int y = 0; y < globalSize1; y++) { - kernelState.setGlobalId(1, y); - - for (int z = 0; z < _settings.range.getGlobalSize(2); z++) { - kernelState.setGlobalId(2, z); - kernelClone.run(); - } - - kernelClone.run(); - } - } - } - } - passId = PASS_ID_COMPLETED_EXECUTION; - } - else { - if (device != JavaDevice.THREAD_POOL && kernel.getExecutionMode() != Kernel.EXECUTION_MODE.JTP) { - throw new AssertionError("unexpected JavaDevice or EXECUTION_MODE"); - } - final int threads = localSize0 * localSize1 * localSize2; - final int numGroups0 = _settings.range.getNumGroups(0); - final int numGroups1 = _settings.range.getNumGroups(1); - final int globalGroups = numGroups0 * numGroups1 * _settings.range.getNumGroups(2); - /** - * This joinBarrier is the barrier that we provide for the kernel threads to rendezvous with the current dispatch thread. - * So this barrier is threadCount+1 wide (the +1 is for the dispatch thread) - */ - final CyclicBarrier joinBarrier = new FJSafeCyclicBarrier(threads + 1); - - /** - * This localBarrier is only ever used by the kernels. If the kernel does not use the barrier the threads - * can get out of sync, we promised nothing in JTP mode. - * - * As with OpenCL all threads within a group must wait at the barrier or none. It is a user error (possible deadlock!) - * if the barrier is in a conditional that is only executed by some of the threads within a group. - * - * Kernel developer must understand this. - * - * This barrier is threadCount wide. We never hit the barrier from the dispatch thread. - */ - final CyclicBarrier localBarrier = new FJSafeCyclicBarrier(threads); - - final ThreadIdSetter threadIdSetter; - - if (_settings.range.getDims() == 1) { - threadIdSetter = new ThreadIdSetter() { - @Override - public void set(KernelState kernelState, int globalGroupId, int threadId) { - // (kernelState, globalGroupId, threadId) ->{ - kernelState.setLocalId(0, (threadId % localSize0)); - kernelState.setGlobalId(0, (threadId + (globalGroupId * threads))); - kernelState.setGroupId(0, globalGroupId); - } - }; - } - else if (_settings.range.getDims() == 2) { - - /** - * Consider a 12x4 grid of 4*2 local groups - * <pre> - * threads = 4*2 = 8 - * localWidth=4 - * localHeight=2 - * globalWidth=12 - * globalHeight=4 - * - * 00 01 02 03 | 04 05 06 07 | 08 09 10 11 - * 12 13 14 15 | 16 17 18 19 | 20 21 22 23 - * ------------+-------------+------------ - * 24 25 26 27 | 28 29 30 31 | 32 33 34 35 - * 36 37 38 39 | 40 41 42 43 | 44 45 46 47 - * - * 00 01 02 03 | 00 01 02 03 | 00 01 02 03 threadIds : [0..7]*6 - * 04 05 06 07 | 04 05 06 07 | 04 05 06 07 - * ------------+-------------+------------ - * 00 01 02 03 | 00 01 02 03 | 00 01 02 03 - * 04 05 06 07 | 04 05 06 07 | 04 05 06 07 - * - * 00 00 00 00 | 01 01 01 01 | 02 02 02 02 groupId[0] : 0..6 - * 00 00 00 00 | 01 01 01 01 | 02 02 02 02 - * ------------+-------------+------------ - * 00 00 00 00 | 01 01 01 01 | 02 02 02 02 - * 00 00 00 00 | 01 01 01 01 | 02 02 02 02 - * - * 00 00 00 00 | 00 00 00 00 | 00 00 00 00 groupId[1] : 0..6 - * 00 00 00 00 | 00 00 00 00 | 00 00 00 00 - * ------------+-------------+------------ - * 01 01 01 01 | 01 01 01 01 | 01 01 01 01 - * 01 01 01 01 | 01 01 01 01 | 01 01 01 01 - * - * 00 01 02 03 | 08 09 10 11 | 16 17 18 19 globalThreadIds == threadId + groupId * threads; - * 04 05 06 07 | 12 13 14 15 | 20 21 22 23 - * ------------+-------------+------------ - * 24 25 26 27 | 32[33]34 35 | 40 41 42 43 - * 28 29 30 31 | 36 37 38 39 | 44 45 46 47 - * - * 00 01 02 03 | 00 01 02 03 | 00 01 02 03 localX = threadId % localWidth; (for globalThreadId 33 = threadId = 01 : 01%4 =1) - * 00 01 02 03 | 00 01 02 03 | 00 01 02 03 - * ------------+-------------+------------ - * 00 01 02 03 | 00[01]02 03 | 00 01 02 03 - * 00 01 02 03 | 00 01 02 03 | 00 01 02 03 - * - * 00 00 00 00 | 00 00 00 00 | 00 00 00 00 localY = threadId /localWidth (for globalThreadId 33 = threadId = 01 : 01/4 =0) - * 01 01 01 01 | 01 01 01 01 | 01 01 01 01 - * ------------+-------------+------------ - * 00 00 00 00 | 00[00]00 00 | 00 00 00 00 - * 01 01 01 01 | 01 01 01 01 | 01 01 01 01 - * - * 00 01 02 03 | 04 05 06 07 | 08 09 10 11 globalX= - * 00 01 02 03 | 04 05 06 07 | 08 09 10 11 groupsPerLineWidth=globalWidth/localWidth (=12/4 =3) - * ------------+-------------+------------ groupInset =groupId%groupsPerLineWidth (=4%3 = 1) - * 00 01 02 03 | 04[05]06 07 | 08 09 10 11 - * 00 01 02 03 | 04 05 06 07 | 08 09 10 11 globalX = groupInset*localWidth+localX (= 1*4+1 = 5) - * - * 00 00 00 00 | 00 00 00 00 | 00 00 00 00 globalY - * 01 01 01 01 | 01 01 01 01 | 01 01 01 01 - * ------------+-------------+------------ - * 02 02 02 02 | 02[02]02 02 | 02 02 02 02 - * 03 03 03 03 | 03 03 03 03 | 03 03 03 03 - * - * </pre> - * Assume we are trying to locate the id's for #33 - * - */ - threadIdSetter = new ThreadIdSetter() { - @Override - public void set(KernelState kernelState, int globalGroupId, int threadId) { - // (kernelState, globalGroupId, threadId) ->{ - kernelState.setLocalId(0, (threadId % localSize0)); // threadId % localWidth = (for 33 = 1 % 4 = 1) - kernelState.setLocalId(1, (threadId / localSize0)); // threadId / localWidth = (for 33 = 1 / 4 == 0) - - final int groupInset = globalGroupId % numGroups0; // 4%3 = 1 - kernelState.setGlobalId(0, ((groupInset * localSize0) + kernelState.getLocalIds()[0])); // 1*4+1=5 - - final int completeLines = (globalGroupId / numGroups0) * localSize1;// (4/3) * 2 - kernelState.setGlobalId(1, (completeLines + kernelState.getLocalIds()[1])); // 2+0 = 2 - kernelState.setGroupId(0, (globalGroupId % numGroups0)); - kernelState.setGroupId(1, (globalGroupId / numGroups0)); - } - }; - } - else if (_settings.range.getDims() == 3) { - //Same as 2D actually turns out that localId[0] is identical for all three dims so could be hoisted out of conditional code - threadIdSetter = new ThreadIdSetter() { - @Override - public void set(KernelState kernelState, int globalGroupId, int threadId) { - // (kernelState, globalGroupId, threadId) ->{ - kernelState.setLocalId(0, (threadId % localSize0)); - - kernelState.setLocalId(1, ((threadId / localSize0) % localSize1)); - - // the thread id's span WxHxD so threadId/(WxH) should yield the local depth - kernelState.setLocalId(2, (threadId / (localSize0 * localSize1))); - - kernelState.setGlobalId(0, (((globalGroupId % numGroups0) * localSize0) + kernelState.getLocalIds()[0])); - - kernelState.setGlobalId(1, - ((((globalGroupId / numGroups0) * localSize1) % globalSize1) + kernelState.getLocalIds()[1])); - - kernelState.setGlobalId(2, - (((globalGroupId / (numGroups0 * numGroups1)) * localSize2) + kernelState.getLocalIds()[2])); - - kernelState.setGroupId(0, (globalGroupId % numGroups0)); - kernelState.setGroupId(1, ((globalGroupId / numGroups0) % numGroups1)); - kernelState.setGroupId(2, (globalGroupId / (numGroups0 * numGroups1))); - } - }; - } - else - throw new IllegalArgumentException("Expected 1,2 or 3 dimensions, found " + _settings.range.getDims()); - for (passId = 0; passId < _settings.passes; passId++) { - if (getCancelState() == CANCEL_STATUS_TRUE) { - break; - } - /** - * Note that we emulate OpenCL by creating one thread per localId (across the group). - * - * So threadCount == range.getLocalSize(0)*range.getLocalSize(1)*range.getLocalSize(2); - * - * For a 1D range of 12 groups of 4 we create 4 threads. One per localId(0). - * - * We also clone the kernel 4 times. One per thread. - * - * We create local barrier which has a width of 4 - * - * Thread-0 handles localId(0) (global 0,4,8) - * Thread-1 handles localId(1) (global 1,5,7) - * Thread-2 handles localId(2) (global 2,6,10) - * Thread-3 handles localId(3) (global 3,7,11) - * - * This allows all threads to synchronize using the local barrier. - * - * Initially the use of local buffers seems broken as the buffers appears to be per Kernel. - * Thankfully Kernel.clone() performs a shallow clone of all buffers (local and global) - * So each of the cloned kernels actually still reference the same underlying local/global buffers. - * - * If the kernel uses local buffers but does not use barriers then it is possible for different groups - * to see mutations from each other (unlike OpenCL), however if the kernel does not us barriers then it - * cannot assume any coherence in OpenCL mode either (the failure mode will be different but still wrong) - * - * So even JTP mode use of local buffers will need to use barriers. Not for the same reason as OpenCL but to keep groups in lockstep. - * - **/ - for (int id = 0; id < threads; id++) { - final int threadId = id; - - /** - * We clone one kernel for each thread. - * - * They will all share references to the same range, localBarrier and global/local buffers because the clone is shallow. - * We need clones so that each thread can assign 'state' (localId/globalId/groupId) without worrying - * about other threads. - */ - final Kernel kernelClone = kernel.clone(); - final KernelState kernelState = kernelClone.getKernelState(); - kernelState.setRange(_settings.range); - kernelState.setPassId(passId); - - if (threads == 1) { - kernelState.disableLocalBarrier(); - } - else { - kernelState.setLocalBarrier(localBarrier); - } - - threadPool.submit( - // () -> { - new Runnable() { - public void run() { - try { - for (int globalGroupId = 0; globalGroupId < globalGroups; globalGroupId++) { - threadIdSetter.set(kernelState, globalGroupId, threadId); - kernelClone.run(); - } - } - catch (RuntimeException | Error e) { - logger.log(Level.SEVERE, "Execution failed", e); - } - finally { - await(joinBarrier); // This thread will rendezvous with dispatch thread here. This is effectively a join. - } - } - }); - } - - await(joinBarrier); // This dispatch thread waits for all worker threads here. - } - passId = PASS_ID_COMPLETED_EXECUTION; - } // execution mode == JTP - } - } finally { - passId = PASS_ID_COMPLETED_EXECUTION; - } - } - - private static void await(CyclicBarrier _barrier) { - try { - _barrier.await(); - } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final BrokenBarrierException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - private KernelArg[] args = null; - - private boolean usesOopConversion = false; - - /** - * - * @param arg - * @return - * @throws AparapiException - */ - private boolean prepareOopConversionBuffer(KernelArg arg) throws AparapiException { - usesOopConversion = true; - final Class<?> arrayClass = arg.getField().getType(); - ClassModel c = null; - boolean didReallocate = false; - - if (arg.getObjArrayElementModel() == null) { - final String tmp = arrayClass.getName().substring(2).replace('/', '.'); - final String arrayClassInDotForm = tmp.substring(0, tmp.length() - 1); - - if (logger.isLoggable(Level.FINE)) { - logger.fine("looking for type = " + arrayClassInDotForm); - } - - // get ClassModel of obj array from entrypt.objectArrayFieldsClasses - c = entryPoint.getObjectArrayFieldsClasses().get(arrayClassInDotForm); - arg.setObjArrayElementModel(c); - } else { - c = arg.getObjArrayElementModel(); - } - assert c != null : "should find class for elements " + arrayClass.getName(); - - final int arrayBaseOffset = UnsafeWrapper.arrayBaseOffset(arrayClass); - final int arrayScale = UnsafeWrapper.arrayIndexScale(arrayClass); - - if (logger.isLoggable(Level.FINEST)) { - logger.finest("Syncing obj array type = " + arrayClass + " cvtd= " + c.getClassWeAreModelling().getName() - + "arrayBaseOffset=" + arrayBaseOffset + " arrayScale=" + arrayScale); - } - - int objArraySize = 0; - Object newRef = null; - try { - newRef = arg.getField().get(kernel); - objArraySize = Array.getLength(newRef); - } catch (final IllegalAccessException e) { - throw new AparapiException(e); - } - - assert (newRef != null) && (objArraySize != 0) : "no data"; - - final int totalStructSize = c.getTotalStructSize(); - final int totalBufferSize = objArraySize * totalStructSize; - - // allocate ByteBuffer if first time or array changed - if ((arg.getObjArrayBuffer() == null) || (newRef != arg.getArray())) { - final ByteBuffer structBuffer = ByteBuffer.allocate(totalBufferSize); - arg.setObjArrayByteBuffer(structBuffer.order(ByteOrder.LITTLE_ENDIAN)); - arg.setObjArrayBuffer(arg.getObjArrayByteBuffer().array()); - didReallocate = true; - if (logger.isLoggable(Level.FINEST)) { - logger.finest("objArraySize = " + objArraySize + " totalStructSize= " + totalStructSize + " totalBufferSize=" - + totalBufferSize); - } - } else { - arg.getObjArrayByteBuffer().clear(); - } - - // copy the fields that the JNI uses - arg.setJavaArray(arg.getObjArrayBuffer()); - arg.setNumElements(objArraySize); - arg.setSizeInBytes(totalBufferSize); - - for (int j = 0; j < objArraySize; j++) { - int sizeWritten = 0; - - final Object object = UnsafeWrapper.getObject(newRef, arrayBaseOffset + (arrayScale * j)); - for (int i = 0; i < c.getStructMemberTypes().size(); i++) { - final TypeSpec t = c.getStructMemberTypes().get(i); - final long offset = c.getStructMemberOffsets().get(i); - - if (logger.isLoggable(Level.FINEST)) { - logger.finest("name = " + c.getStructMembers().get(i).getNameAndTypeEntry().getNameUTF8Entry().getUTF8() + " t= " - + t); - } - - switch (t) { - case I: { - final int x = UnsafeWrapper.getInt(object, offset); - arg.getObjArrayByteBuffer().putInt(x); - sizeWritten += t.getSize(); - break; - } - case F: { - final float x = UnsafeWrapper.getFloat(object, offset); - arg.getObjArrayByteBuffer().putFloat(x); - sizeWritten += t.getSize(); - break; - } - case J: { - final long x = UnsafeWrapper.getLong(object, offset); - arg.getObjArrayByteBuffer().putLong(x); - sizeWritten += t.getSize(); - break; - } - case Z: { - final boolean x = UnsafeWrapper.getBoolean(object, offset); - arg.getObjArrayByteBuffer().put(x == true ? (byte) 1 : (byte) 0); - // Booleans converted to 1 byte C chars for opencl - sizeWritten += TypeSpec.B.getSize(); - break; - } - case B: { - final byte x = UnsafeWrapper.getByte(object, offset); - arg.getObjArrayByteBuffer().put(x); - sizeWritten += t.getSize(); - break; - } - case D: { - throw new AparapiException("Double not implemented yet"); - } - default: - assert true == false : "typespec did not match anything"; - throw new AparapiException("Unhandled type in buffer conversion"); - } - } - - // add padding here if needed - if (logger.isLoggable(Level.FINEST)) { - logger.finest("sizeWritten = " + sizeWritten + " totalStructSize= " + totalStructSize); - } - - assert sizeWritten <= totalStructSize : "wrote too much into buffer"; - - while (sizeWritten < totalStructSize) { - if (logger.isLoggable(Level.FINEST)) { - logger.finest(arg.getName() + " struct pad byte = " + sizeWritten + " totalStructSize= " + totalStructSize); - } - arg.getObjArrayByteBuffer().put((byte) -1); - sizeWritten++; - } - } - - assert arg.getObjArrayByteBuffer().arrayOffset() == 0 : "should be zero"; - - return didReallocate; - } - - private void extractOopConversionBuffer(KernelArg arg) throws AparapiException { - final Class<?> arrayClass = arg.getField().getType(); - final ClassModel c = arg.getObjArrayElementModel(); - assert c != null : "should find class for elements: " + arrayClass.getName(); - assert arg.getArray() != null : "array is null"; - - final int arrayBaseOffset = UnsafeWrapper.arrayBaseOffset(arrayClass); - final int arrayScale = UnsafeWrapper.arrayIndexScale(arrayClass); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("Syncing field:" + arg.getName() + ", bb=" + arg.getObjArrayByteBuffer() + ", type = " + arrayClass); - } - - int objArraySize = 0; - try { - objArraySize = Array.getLength(arg.getField().get(kernel)); - } catch (final IllegalAccessException e) { - throw new AparapiException(e); - } - - assert objArraySize > 0 : "should be > 0"; - - final int totalStructSize = c.getTotalStructSize(); - // int totalBufferSize = objArraySize * totalStructSize; - // assert arg.objArrayBuffer.length == totalBufferSize : "size should match"; - - arg.getObjArrayByteBuffer().rewind(); - - for (int j = 0; j < objArraySize; j++) { - int sizeWritten = 0; - final Object object = UnsafeWrapper.getObject(arg.getArray(), arrayBaseOffset + (arrayScale * j)); - for (int i = 0; i < c.getStructMemberTypes().size(); i++) { - final TypeSpec t = c.getStructMemberTypes().get(i); - final long offset = c.getStructMemberOffsets().get(i); - switch (t) { - case I: { - // read int value from buffer and store into obj in the array - final int x = arg.getObjArrayByteBuffer().getInt(); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("fType = " + t.getShortName() + " x= " + x); - } - UnsafeWrapper.putInt(object, offset, x); - sizeWritten += t.getSize(); - break; - } - case F: { - final float x = arg.getObjArrayByteBuffer().getFloat(); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("fType = " + t.getShortName() + " x= " + x); - } - UnsafeWrapper.putFloat(object, offset, x); - sizeWritten += t.getSize(); - break; - } - case J: { - final long x = arg.getObjArrayByteBuffer().getLong(); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("fType = " + t.getShortName() + " x= " + x); - } - UnsafeWrapper.putLong(object, offset, x); - sizeWritten += t.getSize(); - break; - } - case Z: { - final byte x = arg.getObjArrayByteBuffer().get(); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("fType = " + t.getShortName() + " x= " + x); - } - UnsafeWrapper.putBoolean(object, offset, (x == 1 ? true : false)); - // Booleans converted to 1 byte C chars for open cl - sizeWritten += TypeSpec.B.getSize(); - break; - } - case B: { - final byte x = arg.getObjArrayByteBuffer().get(); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("fType = " + t.getShortName() + " x= " + x); - } - UnsafeWrapper.putByte(object, offset, x); - sizeWritten += t.getSize(); - break; - } - case D: { - throw new AparapiException("Double not implemented yet"); - } - default: - assert true == false : "typespec did not match anything"; - throw new AparapiException("Unhandled type in buffer conversion"); - } - } - - // add padding here if needed - if (logger.isLoggable(Level.FINEST)) { - logger.finest("sizeWritten = " + sizeWritten + " totalStructSize= " + totalStructSize); - } - - assert sizeWritten <= totalStructSize : "wrote too much into buffer"; - - while (sizeWritten < totalStructSize) { - // skip over pad bytes - arg.getObjArrayByteBuffer().get(); - sizeWritten++; - } - } - } - - private void restoreObjects() throws AparapiException { - for (int i = 0; i < argc; i++) { - final KernelArg arg = args[i]; - if ((arg.getType() & ARG_OBJ_ARRAY_STRUCT) != 0) { - extractOopConversionBuffer(arg); - } - } - } - - private boolean updateKernelArrayRefs() throws AparapiException { - boolean needsSync = false; - - for (int i = 0; i < argc; i++) { - final KernelArg arg = args[i]; - try { - if ((arg.getType() & ARG_ARRAY) != 0) { - Object newArrayRef; - newArrayRef = arg.getField().get(kernel); - - if (newArrayRef == null) { - throw new IllegalStateException("Cannot send null refs to kernel, reverting to java"); - } - - String fieldName = arg.getField().getName(); - int arrayLength = Array.getLength(newArrayRef); - Integer privateMemorySize = ClassModel.getPrivateMemorySizeFromField(arg.getField()); - if (privateMemorySize == null) { - privateMemorySize = ClassModel.getPrivateMemorySizeFromFieldName(fieldName); - } - if (privateMemorySize != null) { - if (arrayLength > privateMemorySize) { - throw new IllegalStateException("__private array field " + fieldName + " has illegal length " + arrayLength - + " > " + privateMemorySize); - } - } - - if ((arg.getType() & ARG_OBJ_ARRAY_STRUCT) != 0) { - prepareOopConversionBuffer(arg); - } else { - // set up JNI fields for normal arrays - arg.setJavaArray(newArrayRef); - arg.setNumElements(arrayLength); - arg.setSizeInBytes(arg.getNumElements() * arg.getPrimitiveSize()); - - if (((args[i].getType() & ARG_EXPLICIT) != 0) && puts.contains(newArrayRef)) { - args[i].setType(args[i].getType() | ARG_EXPLICIT_WRITE); - // System.out.println("detected an explicit write " + args[i].name); - puts.remove(newArrayRef); - } - } - - if (newArrayRef != arg.getArray()) { - needsSync = true; - - if (logger.isLoggable(Level.FINE)) { - logger.fine("saw newArrayRef for " + arg.getName() + " = " + newArrayRef + ", newArrayLen = " - + Array.getLength(newArrayRef)); - } - } - - arg.setArray(newArrayRef); - assert arg.getArray() != null : "null array ref"; - } else if ((arg.getType() & ARG_APARAPI_BUFFER) != 0) { - // TODO: check if the 2D/3D array is changed. - // can Arrays.equals help? - needsSync = true; // Always need syn - Object buffer = new Object(); - try { - buffer = arg.getField().get(kernel); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - int numDims = arg.getNumDims(); - Object subBuffer = buffer; - int[] dims = new int[numDims]; - for (int d = 0; d < numDims - 1; d++) { - dims[d] = Array.getLength(subBuffer); - subBuffer = Array.get(subBuffer, 0); - } - dims[numDims - 1] = Array.getLength(subBuffer); - arg.setDims(dims); - - int primitiveSize = getPrimitiveSize(arg.getType()); - int totalElements = 1; - for (int d = 0; d < numDims; d++) { - totalElements *= dims[d]; - } - arg.setJavaBuffer(buffer); - arg.setSizeInBytes(totalElements * primitiveSize); - arg.setArray(buffer); - } - } catch (final IllegalArgumentException e) { - e.printStackTrace(); - } catch (final IllegalAccessException e) { - e.printStackTrace(); - } - } - return needsSync; - } - - @SuppressWarnings("deprecation") - private Kernel executeOpenCL(ExecutionSettings _settings) throws AparapiException { - - // Read the array refs after kernel may have changed them - // We need to do this as input to computing the localSize - assert args != null : "args should not be null"; - final boolean needSync = updateKernelArrayRefs(); - if (needSync && logger.isLoggable(Level.FINE)) { - logger.fine("Need to resync arrays on " + kernel); - } - - // native side will reallocate array buffers if necessary - int returnValue = runKernelJNI(jniContextHandle, _settings.range, needSync, _settings.passes, inBufferRemote, outBufferRemote); - if (returnValue != 0) { - String reason = "OpenCL execution seems to have failed (runKernelJNI returned " + returnValue + ")"; - return fallBackToNextDevice(_settings, new AparapiException(reason)); - } - - if (usesOopConversion == true) { - restoreObjects(); - } - - if (logger.isLoggable(Level.FINE)) { - logger.fine("executeOpenCL completed. " + _settings.range); - } - - return kernel; - } - - @SuppressWarnings("deprecation") - synchronized private Kernel fallBackByExecutionMode(ExecutionSettings _settings) { - isFallBack = true; - if (kernel.hasNextExecutionMode()) { - kernel.tryNextExecutionMode(); - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Trying next execution mode " + kernel.getExecutionMode()); - } - } else { - kernel.setFallbackExecutionMode(); - } - recreateRange(_settings); - return executeInternalInner(_settings); - } - - private void recreateRange(ExecutionSettings _settings) { - if (_settings.range.isLocalIsDerived() && !_settings.legacyExecutionMode) { - Device device = kernel.getTargetDevice(); - Range result; - switch (_settings.range.getDims()) { - case 1: { - result = Range.create(device, _settings.range.getGlobalSize_0()); - break; - } - case 2: { - result = Range.create2D(device, _settings.range.getGlobalSize_0(), _settings.range.getGlobalSize_1()); - break; - } - case 3: { - result = Range.create3D(device, _settings.range.getGlobalSize_0(), _settings.range.getGlobalSize_1(), _settings.range.getGlobalSize_2()); - break; - } - default: { - throw new AssertionError("Range.getDims() = " + _settings.range.getDims()); - } - } - _settings.range = result; - } - } - - private Kernel fallBackToNextDevice(ExecutionSettings _settings, String _reason) { - return fallBackToNextDevice(_settings, new AparapiException(_reason)); - } - - @SuppressWarnings("deprecation") - synchronized private Kernel fallBackToNextDevice(ExecutionSettings _settings, Exception _exception) { - return fallBackToNextDevice(_settings, _exception, false); - } - - @SuppressWarnings("deprecation") - synchronized private Kernel fallBackToNextDevice(ExecutionSettings _settings, Exception _exception, boolean _silently) { - isFallBack = true; - _settings.profile.onEvent(ProfilingEvent.EXECUTED); - if (_settings.legacyExecutionMode) { - if (!_silently && logger.isLoggable(Level.WARNING)) { - logger.warning("Execution mode " + kernel.getExecutionMode() + " failed for " + kernel + ": " + _exception.getMessage()); - _exception.printStackTrace(); - } - return fallBackByExecutionMode(_settings); - } else { - KernelPreferences preferences = KernelManager.instance().getPreferences(kernel); - if (!_silently && logger.isLoggable(Level.WARNING)) { - logger.warning("Device failed for " + kernel + ": " + _exception.getMessage()); - } - - preferences.markPreferredDeviceFailed(); - -// Device nextDevice = preferences.getPreferredDevice(kernel); -// -// if (nextDevice == null) { -// if (!_silently && logger.isLoggable(Level.SEVERE)) { -// logger.severe("No Devices left to try, giving up"); -// } -// throw new RuntimeException(_exception); -// } - if (!_silently && logger.isLoggable(Level.WARNING)) { - _exception.printStackTrace(); - logger.warning("Trying next device: " + describeDevice()); - } - } - - recreateRange(_settings); - return executeInternalInner(_settings); - } - - @SuppressWarnings("deprecation") - public synchronized Kernel execute(String _entrypoint, final Range _range, final int _passes) { - executing = true; - try { - clearCancelMultiPass(); - KernelProfile profile = KernelManager.instance().getProfile(kernel.getClass()); - KernelPreferences preferences = KernelManager.instance().getPreferences(kernel); - boolean legacyExecutionMode = kernel.getExecutionMode() != Kernel.EXECUTION_MODE.AUTO; - - ExecutionSettings settings = new ExecutionSettings(preferences, profile, _entrypoint, _range, _passes, legacyExecutionMode); - // Two Kernels of the same class share the same KernelPreferences object, and since failure (fallback) generally mutates - // the preferences object, we must lock it. Note this prevents two Kernels of the same class executing simultaneously. - synchronized (preferences) { - return executeInternalOuter(settings); - } - } finally { - executing = false; - clearCancelMultiPass(); - } - } - - private synchronized Kernel executeInternalOuter(ExecutionSettings _settings) { - try { - return executeInternalInner(_settings); - } finally { - if (kernel.isAutoCleanUpArrays() &&_settings.range.getGlobalSize_0() != 0) { - cleanUpArrays(); - } - } - } - - @SuppressWarnings("deprecation") - private synchronized Kernel executeInternalInner(ExecutionSettings _settings) { - - if (_settings.range == null) { - throw new IllegalStateException("range can't be null"); - } - - EXECUTION_MODE requestedExecutionMode = kernel.getExecutionMode(); - - if (requestedExecutionMode.isOpenCL() && _settings.range.getDevice() != null && !(_settings.range.getDevice() instanceof OpenCLDevice)) { - fallBackToNextDevice(_settings, "OpenCL EXECUTION_MODE was requested but Device supplied was not an OpenCLDevice"); - } - - Device device = _settings.range.getDevice(); - boolean userSpecifiedDevice = true; - if (device == null) { - userSpecifiedDevice = false; - if (!_settings.legacyExecutionMode) { - device = _settings.preferences.getPreferredDevice(kernel); - if (device == null) { - // the default fallback when KernelPreferences has run out of options is JTP - device = JavaDevice.THREAD_POOL; - } - } else { - if (requestedExecutionMode == EXECUTION_MODE.JTP) { - device = JavaDevice.THREAD_POOL; - } else if (requestedExecutionMode == EXECUTION_MODE.SEQ) { - device = JavaDevice.SEQUENTIAL; - } - } - } else { - boolean compatible = isDeviceCompatible(device); - if (!compatible) { - throw new AssertionError("user supplied Device incompatible with current EXECUTION_MODE or getTargetDevice(); device = " - + device.getShortDescription() + "; kernel = " + kernel); - } - } - - try { - OpenCLDevice openCLDevice = device instanceof OpenCLDevice ? (OpenCLDevice) device : null; - - int jniFlags = 0; - // for legacy reasons use old logic where Kernel.EXECUTION_MODE is not AUTO - if (_settings.legacyExecutionMode && !userSpecifiedDevice && requestedExecutionMode.isOpenCL()) { - if (requestedExecutionMode.equals(EXECUTION_MODE.GPU)) { - // Get the best GPU - openCLDevice = (OpenCLDevice) KernelManager.DeprecatedMethods.bestGPU(); - jniFlags |= JNI_FLAG_USE_GPU; // this flag might be redundant now. - if (openCLDevice == null) { - return fallBackToNextDevice(_settings, "GPU request can't be honored, no GPU device"); - } - } else if (requestedExecutionMode.equals(EXECUTION_MODE.ACC)) { - // Get the best ACC - openCLDevice = (OpenCLDevice) KernelManager.DeprecatedMethods.bestACC(); - jniFlags |= JNI_FLAG_USE_ACC; // this flag might be redundant now. - if (openCLDevice == null) { - return fallBackToNextDevice(_settings, "ACC request can't be honored, no ACC device"); - } - } else { - // We fetch the first CPU device - openCLDevice = (OpenCLDevice) KernelManager.DeprecatedMethods.firstDevice(Device.TYPE.CPU); - if (openCLDevice == null) { - return fallBackToNextDevice(_settings, "CPU request can't be honored, no CPU device"); - } - } - } else { - if (device.getType() == Device.TYPE.GPU) { - jniFlags |= JNI_FLAG_USE_GPU; // this flag might be redundant now. - } else if (device.getType() == Device.TYPE.ACC) { - jniFlags |= JNI_FLAG_USE_ACC; // this flag might be redundant now. - } - } - if (device == null && openCLDevice != null) { - device = openCLDevice; - } - assert device != null : "No device available"; - _settings.profile.onStart(device); - /* for backward compatibility reasons we still honor execution mode */ - boolean isOpenCl = requestedExecutionMode.isOpenCL() || device instanceof OpenCLDevice; - if (isOpenCl) { - if ((entryPoint == null) || (isFallBack)) { - if (entryPoint == null) { - try { - final ClassModel classModel = ClassModel.createClassModel(kernel.getClass()); - entryPoint = classModel.getEntrypoint(_settings.entrypoint, kernel); - _settings.profile.onEvent(ProfilingEvent.CLASS_MODEL_BUILT); - } catch (final Exception exception) { - _settings.profile.onEvent(ProfilingEvent.CLASS_MODEL_BUILT); - return fallBackToNextDevice(_settings, exception); - } - } - - if ((entryPoint != null)) { - synchronized (Kernel.class) { // This seems to be needed because of a race condition uncovered with issue #68 http://code.google.com/p/aparapi/issues/detail?id=68 - - // jniFlags |= (Config.enableProfiling ? JNI_FLAG_ENABLE_PROFILING : 0); - // jniFlags |= (Config.enableProfilingCSV ? JNI_FLAG_ENABLE_PROFILING_CSV | JNI_FLAG_ENABLE_PROFILING : 0); - // jniFlags |= (Config.enableVerboseJNI ? JNI_FLAG_ENABLE_VERBOSE_JNI : 0); - // jniFlags |= (Config.enableVerboseJNIOpenCLResourceTracking ? JNI_FLAG_ENABLE_VERBOSE_JNI_OPENCL_RESOURCE_TRACKING :0); - // jniFlags |= (kernel.getExecutionMode().equals(Kernel.EXECUTION_MODE.GPU) ? JNI_FLAG_USE_GPU : 0); - // Init the device to check capabilities before emitting the - // code that requires the capabilities. - jniContextHandle = initJNI(kernel, openCLDevice, jniFlags); // openCLDevice will not be null here - _settings.profile.onEvent(ProfilingEvent.INIT_JNI); - } // end of synchronized! issue 68 - - if (jniContextHandle == 0) { - return fallBackToNextDevice(_settings, "initJNI failed to return a valid handle"); - } - - final String extensions = getExtensionsJNI(jniContextHandle); - capabilitiesSet = new HashSet<String>(); - - final StringTokenizer strTok = new StringTokenizer(extensions); - while (strTok.hasMoreTokens()) { - capabilitiesSet.add(strTok.nextToken()); - } - - if (logger.isLoggable(Level.FINE)) { - logger.fine("Capabilities initialized to :" + capabilitiesSet.toString()); - } - - if (entryPoint.requiresDoublePragma() && !hasFP64Support()) { - return fallBackToNextDevice(_settings, "FP64 required but not supported"); - } - - if (entryPoint.requiresByteAddressableStorePragma() && !hasByteAddressableStoreSupport()) { - return fallBackToNextDevice(_settings, "Byte addressable stores required but not supported"); - } - - final boolean all32AtomicsAvailable = hasGlobalInt32BaseAtomicsSupport() - && hasGlobalInt32ExtendedAtomicsSupport() && hasLocalInt32BaseAtomicsSupport() - && hasLocalInt32ExtendedAtomicsSupport(); - - if (entryPoint.requiresAtomic32Pragma() && !all32AtomicsAvailable) { - - return fallBackToNextDevice(_settings, "32 bit Atomics required but not supported"); - } - - String openCL; - synchronized (openCLCache) { - openCL = openCLCache.get(kernel.getClass()); - if (openCL == null) { - try { - openCL = KernelWriter.writeToString(entryPoint); - if (logger.isLoggable(Level.INFO)) { - logger.info(openCL); - } - else if (Config.enableShowGeneratedOpenCL) { - System.out.println(openCL); - } - _settings.profile.onEvent(ProfilingEvent.OPENCL_GENERATED); - openCLCache.put(kernel.getClass(), openCL); - } - catch (final CodeGenException codeGenException) { - openCLCache.put(kernel.getClass(), CODE_GEN_ERROR_MARKER); - _settings.profile.onEvent(ProfilingEvent.OPENCL_GENERATED); - return fallBackToNextDevice(_settings, codeGenException); - } - } - else { - if (openCL.equals(CODE_GEN_ERROR_MARKER)) { - _settings.profile.onEvent(ProfilingEvent.OPENCL_GENERATED); - boolean silently = true; // since we must have already reported the CodeGenException - return fallBackToNextDevice(_settings, null, silently); - } - } - } - - // Send the string to OpenCL to compile it, or if the compiled binary is already cached on JNI side just empty string to use cached binary - long handle; - if (BINARY_CACHING_DISABLED) { - handle = buildProgramJNI(jniContextHandle, openCL, ""); - } else { - synchronized (seenBinaryKeys) { - String binaryKey = kernel.getClass().getName() + ":" + device.getDeviceId(); - if (seenBinaryKeys.contains(binaryKey)) { - // use cached binary - logger.log(Level.INFO, "reusing cached binary for " + binaryKey); - handle = buildProgramJNI(jniContextHandle, "", binaryKey); - } - else { - // create and cache binary - logger.log(Level.INFO, "compiling new binary for " + binaryKey); - handle = buildProgramJNI(jniContextHandle, openCL, binaryKey); - seenBinaryKeys.add(binaryKey); - } - } - } - _settings.profile.onEvent(ProfilingEvent.OPENCL_COMPILED); - if (handle == 0) { - return fallBackToNextDevice(_settings, "OpenCL compile failed"); - } - - args = new KernelArg[entryPoint.getReferencedFields().size()]; - int i = 0; - - for (final Field field : entryPoint.getReferencedFields()) { - try { - field.setAccessible(true); - args[i] = new KernelArg(); - args[i].setName(field.getName()); - args[i].setField(field); - if ((field.getModifiers() & Modifier.STATIC) == Modifier.STATIC) { - args[i].setType(args[i].getType() | ARG_STATIC); - } - - final Class<?> type = field.getType(); - if (type.isArray()) { - - if (field.getAnnotation(Local.class) != null || args[i].getName().endsWith(Kernel.LOCAL_SUFFIX)) { - args[i].setType(args[i].getType() | ARG_LOCAL); - } else if ((field.getAnnotation(Constant.class) != null) - || args[i].getName().endsWith(Kernel.CONSTANT_SUFFIX)) { - args[i].setType(args[i].getType() | ARG_CONSTANT); - } else { - args[i].setType(args[i].getType() | ARG_GLOBAL); - } - if (isExplicit()) { - args[i].setType(args[i].getType() | ARG_EXPLICIT); - } - // for now, treat all write arrays as read-write, see bugzilla issue 4859 - // we might come up with a better solution later - args[i].setType(args[i].getType() - | (entryPoint.getArrayFieldAssignments().contains(field.getName()) ? (ARG_WRITE | ARG_READ) : 0)); - args[i].setType(args[i].getType() - | (entryPoint.getArrayFieldAccesses().contains(field.getName()) ? ARG_READ : 0)); - // args[i].type |= ARG_GLOBAL; - - if (type.getName().startsWith("[L")) { - args[i].setArray(null); // will get updated in updateKernelArrayRefs - args[i].setType(args[i].getType() - | (ARG_ARRAY | ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)); - - if (logger.isLoggable(Level.FINE)) { - logger.fine("tagging " + args[i].getName() + " as (ARG_ARRAY | ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)"); - } - } else if (type.getName().startsWith("[[")) { - - try { - setMultiArrayType(args[i], type); - } catch (AparapiException e) { - return fallBackToNextDevice(_settings, "failed to set kernel arguement " - + args[i].getName() + ". Aparapi only supports 2D and 3D arrays."); - } - } else { - - args[i].setArray(null); // will get updated in updateKernelArrayRefs - args[i].setType(args[i].getType() | ARG_ARRAY); - - args[i].setType(args[i].getType() | (type.isAssignableFrom(float[].class) ? ARG_FLOAT : 0)); - args[i].setType(args[i].getType() | (type.isAssignableFrom(int[].class) ? ARG_INT : 0)); - args[i].setType(args[i].getType() | (type.isAssignableFrom(boolean[].class) ? ARG_BOOLEAN : 0)); - args[i].setType(args[i].getType() | (type.isAssignableFrom(byte[].class) ? ARG_BYTE : 0)); - args[i].setType(args[i].getType() | (type.isAssignableFrom(char[].class) ? ARG_CHAR : 0)); - args[i].setType(args[i].getType() | (type.isAssignableFrom(double[].class) ? ARG_DOUBLE : 0)); - args[i].setType(args[i].getType() | (type.isAssignableFrom(long[].class) ? ARG_LONG : 0)); - args[i].setType(args[i].getType() | (type.isAssignableFrom(short[].class) ? ARG_SHORT : 0)); - - // arrays whose length is used will have an int arg holding - // the length as a kernel param - if (entryPoint.getArrayFieldArrayLengthUsed().contains(args[i].getName())) { - args[i].setType(args[i].getType() | ARG_ARRAYLENGTH); - } - - if (type.getName().startsWith("[L")) { - args[i].setType(args[i].getType() | (ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)); - if (logger.isLoggable(Level.FINE)) { - logger.fine("tagging " + args[i].getName() - + " as (ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)"); - } - } - } - } else if (type.isAssignableFrom(float.class)) { - args[i].setType(args[i].getType() | ARG_PRIMITIVE); - args[i].setType(args[i].getType() | ARG_FLOAT); - } else if (type.isAssignableFrom(int.class)) { - args[i].setType(args[i].getType() | ARG_PRIMITIVE); - args[i].setType(args[i].getType() | ARG_INT); - } else if (type.isAssignableFrom(double.class)) { - args[i].setType(args[i].getType() | ARG_PRIMITIVE); - args[i].setType(args[i].getType() | ARG_DOUBLE); - } else if (type.isAssignableFrom(long.class)) { - args[i].setType(args[i].getType() | ARG_PRIMITIVE); - args[i].setType(args[i].getType() | ARG_LONG); - } else if (type.isAssignableFrom(boolean.class)) { - args[i].setType(args[i].getType() | ARG_PRIMITIVE); - args[i].setType(args[i].getType() | ARG_BOOLEAN); - } else if (type.isAssignableFrom(byte.class)) { - args[i].setType(args[i].getType() | ARG_PRIMITIVE); - args[i].setType(args[i].getType() | ARG_BYTE); - } else if (type.isAssignableFrom(char.class)) { - args[i].setType(args[i].getType() | ARG_PRIMITIVE); - args[i].setType(args[i].getType() | ARG_CHAR); - } else if (type.isAssignableFrom(short.class)) { - args[i].setType(args[i].getType() | ARG_PRIMITIVE); - args[i].setType(args[i].getType() | ARG_SHORT); - } - // System.out.printf("in execute, arg %d %s %08x\n", i,args[i].name,args[i].type ); - } catch (final IllegalArgumentException e) { - e.printStackTrace(); - } - - args[i].setPrimitiveSize(getPrimitiveSize(args[i].getType())); - - if (logger.isLoggable(Level.FINE)) { - logger.fine("arg " + i + ", " + args[i].getName() + ", type=" + Integer.toHexString(args[i].getType()) - + ", primitiveSize=" + args[i].getPrimitiveSize()); - } - - i++; - } - - // at this point, i = the actual used number of arguments - // (private buffers do not get treated as arguments) - - argc = i; - - setArgsJNI(jniContextHandle, args, argc); - _settings.profile.onEvent(ProfilingEvent.PREPARE_EXECUTE); - try { - executeOpenCL(_settings); - isFallBack = false; - } catch (final AparapiException e) { - fallBackToNextDevice(_settings, e); - } - } else { // (entryPoint != null) && !entryPoint.shouldFallback() - fallBackToNextDevice(_settings, "failed to locate entrypoint"); - } - } else { // (entryPoint == null) || (isFallBack) - try { - executeOpenCL(_settings); - isFallBack = false; - } catch (final AparapiException e) { - fallBackToNextDevice(_settings, e); - } - } - } else { // isOpenCL - if (!(device instanceof JavaDevice)) { - fallBackToNextDevice(_settings, "Non-OpenCL Kernel.EXECUTION_MODE requested but device is not a JavaDevice "); - } - executeJava(_settings, (JavaDevice) device); - } - - if (Config.enableExecutionModeReporting) { - System.out.println("execution complete: " + kernel); - } - - return kernel; - } - finally { - _settings.profile.onEvent(ProfilingEvent.EXECUTED); - maybeReportProfile(_settings); - } - } - - @Override - public String toString() { - return "KernelRunner{" + kernel + "}"; - } - - private String describeDevice() { - Device device = KernelManager.instance().getPreferences(kernel).getPreferredDevice(kernel); - return (device == null) ? "<default fallback>" : device.getShortDescription(); - } - - private void maybeReportProfile(ExecutionSettings _settings) { - if (Config.dumpProfileOnExecution) { - StringBuilder report = new StringBuilder(); - report.append(KernelDeviceProfile.getTableHeader()).append('\n'); - report.append(_settings.profile.getLastDeviceProfile().getLastAsTableRow()); - System.out.println(report); - } - } - - @SuppressWarnings("deprecation") - private boolean isDeviceCompatible(Device device) { - Kernel.EXECUTION_MODE mode = kernel.getExecutionMode(); - if (mode != Kernel.EXECUTION_MODE.AUTO) { - switch (device.getType()) { - case GPU: - return mode == Kernel.EXECUTION_MODE.GPU; - case CPU: - return mode == Kernel.EXECUTION_MODE.CPU; - case JTP: - return mode == Kernel.EXECUTION_MODE.JTP; - case SEQ: - return mode == Kernel.EXECUTION_MODE.SEQ; - case ACC: - return mode == Kernel.EXECUTION_MODE.ACC; - default: - return false; - } - } else { - return (device == kernel.getTargetDevice()); - } - } - - public int getCancelState() { - return inBufferRemoteInt.get(0); - } - - public void cancelMultiPass() { - inBufferRemoteInt.put(0, CANCEL_STATUS_TRUE); - } - - private void clearCancelMultiPass() { - inBufferRemoteInt.put(0, CANCEL_STATUS_FALSE); - } - - /** - * Returns the index of the current pass, or one of two special constants with negative values to indicate special progress states. Those constants are - * {@link #PASS_ID_PREPARING_EXECUTION} to indicate that the Kernel has started executing but not reached the initial pass, or - * {@link #PASS_ID_COMPLETED_EXECUTION} to indicate that execution is complete (possibly due to early termination via {@link #cancelMultiPass()}), i.e. the Kernel - * is idle. {@link #PASS_ID_COMPLETED_EXECUTION} is also returned before the first execution has been invoked. - * - * <p>This can be used, for instance, to update a visual progress bar. - * - * @see #execute(String, Range, int) - */ - public int getCurrentPass() { - if (!executing) { - return PASS_ID_COMPLETED_EXECUTION; - } - - if (kernel.isRunningCL()) { - return getCurrentPassRemote(); - } else { - return getCurrentPassLocal(); - } - } - - /** - * True while any of the {@code execute()} methods are in progress. - */ - public boolean isExecuting() { - return executing; - } - - protected int getCurrentPassRemote() { - return outBufferRemoteInt.get(0); - } - - private int getCurrentPassLocal() { - return passId; - } - - private int getPrimitiveSize(int type) { - if ((type & ARG_FLOAT) != 0) { - return 4; - } else if ((type & ARG_INT) != 0) { - return 4; - } else if ((type & ARG_BYTE) != 0) { - return 1; - } else if ((type & ARG_CHAR) != 0) { - return 2; - } else if ((type & ARG_BOOLEAN) != 0) { - return 1; - } else if ((type & ARG_SHORT) != 0) { - return 2; - } else if ((type & ARG_LONG) != 0) { - return 8; - } else if ((type & ARG_DOUBLE) != 0) { - return 8; - } - return 0; - } - - private void setMultiArrayType(KernelArg arg, Class<?> type) throws AparapiException { - arg.setType(arg.getType() | (ARG_WRITE | ARG_READ | ARG_APARAPI_BUFFER)); - int numDims = 0; - while (type.getName().startsWith("[[[[")) { - throw new AparapiException("Aparapi only supports 2D and 3D arrays."); - } - arg.setType(arg.getType() | ARG_ARRAYLENGTH); - while (type.getName().charAt(numDims) == '[') { - numDims++; - } - arg.setNumDims(numDims); - arg.setJavaBuffer(null); // will get updated in updateKernelArrayRefs - arg.setArray(null); // will get updated in updateKernelArrayRefs - - Class<?> elementType = arg.getField().getType(); - while (elementType.isArray()) { - elementType = elementType.getComponentType(); - } - - if (elementType.isAssignableFrom(float.class)) { - arg.setType(arg.getType() | ARG_FLOAT); - } else if (elementType.isAssignableFrom(int.class)) { - arg.setType(arg.getType() | ARG_INT); - } else if (elementType.isAssignableFrom(boolean.class)) { - arg.setType(arg.getType() | ARG_BOOLEAN); - } else if (elementType.isAssignableFrom(byte.class)) { - arg.setType(arg.getType() | ARG_BYTE); - } else if (elementType.isAssignableFrom(char.class)) { - arg.setType(arg.getType() | ARG_CHAR); - } else if (elementType.isAssignableFrom(double.class)) { - arg.setType(arg.getType() | ARG_DOUBLE); - } else if (elementType.isAssignableFrom(long.class)) { - arg.setType(arg.getType() | ARG_LONG); - } else if (elementType.isAssignableFrom(short.class)) { - arg.setType(arg.getType() | ARG_SHORT); - } - } - - private final Set<Object> puts = new HashSet<Object>(); - - /** - * Enqueue a request to return this array from the GPU. This method blocks until the array is available. - * <br/> - * Note that <code>Kernel.put(type [])</code> calls will delegate to this call. - * <br/> - * Package public - * - * @param array - * It is assumed that this parameter is indeed an array (of int, float, short etc). - * - * @see Kernel#get(int[] arr) - * @see Kernel#get(float[] arr) - * @see Kernel#get(double[] arr) - * @see Kernel#get(long[] arr) - * @see Kernel#get(char[] arr) - * @see Kernel#get(boolean[] arr) - */ - public void get(Object array) { - if (explicit && (kernel.isRunningCL())) { - // Only makes sense when we are using OpenCL - getJNI(jniContextHandle, array); - } - } - - public List<ProfileInfo> getProfileInfo() { - if (explicit && (kernel.isRunningCL())) { - // Only makes sense when we are using OpenCL - return (getProfileInfoJNI(jniContextHandle)); - } else { - return (null); - } - } - - /** - * Tag this array so that it is explicitly enqueued before the kernel is executed. <br/> - * Note that <code>Kernel.put(type [])</code> calls will delegate to this call. <br/> - * Package public - * - * @param array - * It is assumed that this parameter is indeed an array (of int, float, short etc). - * @see Kernel#put(int[] arr) - * @see Kernel#put(float[] arr) - * @see Kernel#put(double[] arr) - * @see Kernel#put(long[] arr) - * @see Kernel#put(char[] arr) - * @see Kernel#put(boolean[] arr) - */ - - public void put(Object array) { - if (explicit && (kernel.isRunningCL())) { - // Only makes sense when we are using OpenCL - puts.add(array); - } - } - - private boolean explicit = false; - - public void setExplicit(boolean _explicit) { - explicit = _explicit; - } - - public boolean isExplicit() { - return (explicit); - } - - private static class ExecutionSettings { - final KernelPreferences preferences; - final KernelProfile profile; - final String entrypoint; - Range range; - final int passes; - final boolean legacyExecutionMode; - - private ExecutionSettings(KernelPreferences preferences, KernelProfile profile, String entrypoint, Range range, int passes, boolean legacyExecutionMode) { - this.preferences = preferences; - this.profile = profile; - this.entrypoint = entrypoint; - this.range = range; - this.passes = passes; - this.legacyExecutionMode = legacyExecutionMode; - } - - @Override - public String toString() { - return "ExecutionSettings{" + - "preferences=" + preferences + - ", profile=" + profile + - ", entrypoint='" + entrypoint + '\'' + - ", range=" + range + - ", passes=" + passes + - ", legacyExecutionMode=" + legacyExecutionMode + - '}'; - } - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.kernel; + +import com.aparapi.*; +import com.aparapi.Kernel.Constant; +import com.aparapi.Kernel.*; +import com.aparapi.device.*; +import com.aparapi.internal.annotation.*; +import com.aparapi.internal.exception.*; +import com.aparapi.internal.instruction.InstructionSet.*; +import com.aparapi.internal.jni.*; +import com.aparapi.internal.model.*; +import com.aparapi.internal.util.*; +import com.aparapi.internal.writer.*; +import com.aparapi.opencl.*; + +import java.lang.reflect.*; +import java.nio.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.ForkJoinPool.*; +import java.util.logging.*; + +/** + * The class is responsible for executing <code>Kernel</code> implementations. <br/> + * + * The <code>KernelRunner</code> is the real workhorse for Aparapi. Each <code>Kernel</code> instance creates a single + * <code>KernelRunner</code> to encapsulate state and to help coordinate interactions between the <code>Kernel</code> + * and it's execution logic.<br/> + * + * The <code>KernelRunner</code> is created <i>lazily</i> as a result of calling <code>Kernel.execute()</code>. A this + * time the <code>ExecutionMode</code> is consulted to determine the default requested mode. This will dictate how + * the <code>KernelRunner</code> will attempt to execute the <code>Kernel</code> + * + * @see com.aparapi.Kernel#execute(int _globalSize) + * + * @author gfrost + * + */ +public class KernelRunner extends KernelRunnerJNI{ + + public static boolean BINARY_CACHING_DISABLED = false; + + private static final int MINIMUM_ARRAY_SIZE = 1; + + /** @see #getCurrentPass() */ + @UsedByJNICode public static final int PASS_ID_PREPARING_EXECUTION = -2; + /** @see #getCurrentPass() */ + @UsedByJNICode public static final int PASS_ID_COMPLETED_EXECUTION = -1; + @UsedByJNICode public static final int CANCEL_STATUS_FALSE = 0; + @UsedByJNICode public static final int CANCEL_STATUS_TRUE = 1; + private static final String CODE_GEN_ERROR_MARKER = CodeGenException.class.getName(); + + private static Logger logger = Logger.getLogger(Config.getLoggerName()); + + private long jniContextHandle = 0; + + private final Kernel kernel; + + private Entrypoint entryPoint; + + private int argc; + + // may be read by a thread other than the control thread, hence volatile + private volatile boolean executing; + + // may be read by a thread other than the control thread, hence volatile + private volatile int passId = PASS_ID_PREPARING_EXECUTION; + + /** + * A direct ByteBuffer used for asynchronous intercommunication between java and JNI C code. + * + * <p> + * At present this is a 4 byte buffer to be interpreted as an int[1], used for passing from java to C a single integer interpreted as a cancellation indicator. + */ + private final ByteBuffer inBufferRemote; + private final IntBuffer inBufferRemoteInt; + + /** A direct ByteBuffer used for asynchronous intercommunication between java and JNI C code. + * <p> + * At present this is a 4 byte buffer to be interpreted as an int[1], used for passing from C to java a single integer interpreted as a + * the current pass id. + */ + private final ByteBuffer outBufferRemote; + private final IntBuffer outBufferRemoteInt; + + private boolean isFallBack = false; // If isFallBack, rebuild the kernel (necessary?) + + private static final ForkJoinWorkerThreadFactory lowPriorityThreadFactory = new ForkJoinWorkerThreadFactory(){ + @Override public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + ForkJoinWorkerThread newThread = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool); + newThread.setPriority(Thread.MIN_PRIORITY); + return newThread; + } + }; + + private static final ForkJoinPool threadPool = new ForkJoinPool(Runtime.getRuntime().availableProcessors(), + lowPriorityThreadFactory, null, false); + private static HashMap<Class<? extends Kernel>, String> openCLCache = new HashMap<>(); + private static LinkedHashSet<String> seenBinaryKeys = new LinkedHashSet<>(); + + /** + * Create a KernelRunner for a specific Kernel instance. + * + * @param _kernel + */ + public KernelRunner(Kernel _kernel) { + kernel = _kernel; + + inBufferRemote = ByteBuffer.allocateDirect(4); + outBufferRemote = ByteBuffer.allocateDirect(4); + + inBufferRemote.order(ByteOrder.nativeOrder()); + outBufferRemote.order(ByteOrder.nativeOrder()); + + inBufferRemoteInt = inBufferRemote.asIntBuffer(); + outBufferRemoteInt = outBufferRemote.asIntBuffer(); + + KernelManager.instance(); // ensures static initialization of KernelManager + } + + /** + * @see Kernel#cleanUpArrays(). + */ + public void cleanUpArrays() { + if (args != null && kernel.isRunningCL()) { + for (KernelArg arg : args) { + if ((arg.getType() & KernelRunnerJNI.ARG_ARRAY) != 0) { + Field field = arg.getField(); + if (field != null && field.getType().isArray() && !Modifier.isFinal(field.getModifiers())) { + field.setAccessible(true); + Class<?> componentType = field.getType().getComponentType(); + Object newValue = Array.newInstance(componentType, MINIMUM_ARRAY_SIZE); + try { + field.set(kernel, newValue); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + } + kernel.execute(0); + } else if (kernel.isRunningCL()) { + logger.log(Level.SEVERE, "KernelRunner#cleanUpArrays() could not execute as no args available (Kernel has not been executed?)"); + } + } + + /** + * <code>Kernel.dispose()</code> delegates to <code>KernelRunner.dispose()</code> which delegates to <code>disposeJNI()</code> to actually close JNI data structures.<br/> + * + * @see KernelRunnerJNI#disposeJNI(long) + */ + public synchronized void dispose() { + if (kernel.isRunningCL()) { + disposeJNI(jniContextHandle); + seenBinaryKeys.clear(); + } + // We are using a shared pool, so there's no need no shutdown it when kernel is disposed + // threadPool.shutdownNow(); + } + + private Set<String> capabilitiesSet; + + boolean hasFP64Support() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return (capabilitiesSet.contains(OpenCL.CL_KHR_FP64)); + } + + boolean hasSelectFPRoundingModeSupport() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_SELECT_FPROUNDING_MODE); + } + + boolean hasGlobalInt32BaseAtomicsSupport() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_GLOBAL_INT32_BASE_ATOMICS); + } + + boolean hasGlobalInt32ExtendedAtomicsSupport() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_GLOBAL_INT32_EXTENDED_ATOMICS); + } + + boolean hasLocalInt32BaseAtomicsSupport() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_LOCAL_INT32_BASE_ATOMICS); + } + + boolean hasLocalInt32ExtendedAtomicsSupport() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_LOCAL_INT32_EXTENDED_ATOMICS); + } + + boolean hasInt64BaseAtomicsSupport() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_INT64_BASE_ATOMICS); + } + + boolean hasInt64ExtendedAtomicsSupport() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_INT64_EXTENDED_ATOMICS); + } + + boolean has3DImageWritesSupport() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_3D_IMAGE_WRITES); + } + + boolean hasByteAddressableStoreSupport() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_BYTE_ADDRESSABLE_SUPPORT); + } + + boolean hasFP16Support() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_FP16); + } + + boolean hasGLSharingSupport() { + if (capabilitiesSet == null) { + throw new IllegalStateException("Capabilities queried before they were initialized"); + } + return capabilitiesSet.contains(OpenCL.CL_KHR_GL_SHARING); + } + + private static final class FJSafeCyclicBarrier extends CyclicBarrier{ + FJSafeCyclicBarrier(final int threads) { + super(threads); + } + + @Override public int await() throws InterruptedException, BrokenBarrierException { + class Awaiter implements ManagedBlocker{ + private int value; + + private boolean released; + + @Override public boolean block() throws InterruptedException { + try { + value = superAwait(); + released = true; + return true; + } catch (final BrokenBarrierException e) { + throw new RuntimeException(e); + } + } + + @Override public boolean isReleasable() { + return released; + } + + int getValue() { + return value; + } + } + final Awaiter awaiter = new Awaiter(); + ForkJoinPool.managedBlock(awaiter); + return awaiter.getValue(); + } + + int superAwait() throws InterruptedException, BrokenBarrierException { + return super.await(); + } + } + + // @FunctionalInterface + private interface ThreadIdSetter{ + void set(KernelState kernelState, int globalGroupId, int threadId); + } + + /** + * Execute using a Java thread pool, or sequentially, or using an alternative algorithm, usually as a result of failing to compile or execute OpenCL + */ + @SuppressWarnings("deprecation") + protected void executeJava(ExecutionSettings _settings, Device device) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("executeJava: range = " + _settings.range + ", device = " + device); + } + boolean legacySequentialMode = kernel.getExecutionMode().equals(Kernel.EXECUTION_MODE.SEQ); + + passId = PASS_ID_PREPARING_EXECUTION; + _settings.profile.onEvent(ProfilingEvent.PREPARE_EXECUTE); + + try { + if (device == JavaDevice.ALTERNATIVE_ALGORITHM) { + if (kernel.hasFallbackAlgorithm()) { + for (passId = 0; passId < _settings.passes; ++passId) { + kernel.executeFallbackAlgorithm(_settings.range, passId); + } + } else { + boolean silently = true; // not having an alternative algorithm is the normal state, and does not need reporting + fallBackToNextDevice(_settings, (Exception) null, silently); + } + } else { + final int localSize0 = _settings.range.getLocalSize(0); + final int localSize1 = _settings.range.getLocalSize(1); + final int localSize2 = _settings.range.getLocalSize(2); + final int globalSize1 = _settings.range.getGlobalSize(1); + if (legacySequentialMode || device == JavaDevice.SEQUENTIAL) { + /** + * SEQ mode is useful for testing trivial logic, but kernels which use SEQ mode cannot be used if the + * product of localSize(0..3) is >1. So we can use multi-dim ranges but only if the local size is 1 in all dimensions. + * + * As a result of this barrier is only ever 1 work item wide and probably should be turned into a no-op. + * + * So we need to check if the range is valid here. If not we have no choice but to punt. + */ + if ((localSize0 * localSize1 * localSize2) > 1) { + throw new IllegalStateException("Can't run range with group size >1 sequentially. Barriers would deadlock!"); + } + + final Kernel kernelClone = kernel.clone(); + final KernelState kernelState = kernelClone.getKernelState(); + + kernelState.setRange(_settings.range); + kernelState.setGroupId(0, 0); + kernelState.setGroupId(1, 0); + kernelState.setGroupId(2, 0); + kernelState.setLocalId(0, 0); + kernelState.setLocalId(1, 0); + kernelState.setLocalId(2, 0); + kernelState.setLocalBarrier(new FJSafeCyclicBarrier(1)); + + for (passId = 0; passId < _settings.passes; passId++) { + if (getCancelState() == CANCEL_STATUS_TRUE) { + break; + } + kernelState.setPassId(passId); + + if (_settings.range.getDims() == 1) { + for (int id = 0; id < _settings.range.getGlobalSize(0); id++) { + kernelState.setGlobalId(0, id); + kernelClone.run(); + } + } + else if (_settings.range.getDims() == 2) { + for (int x = 0; x < _settings.range.getGlobalSize(0); x++) { + kernelState.setGlobalId(0, x); + + for (int y = 0; y < globalSize1; y++) { + kernelState.setGlobalId(1, y); + kernelClone.run(); + } + } + } + else if (_settings.range.getDims() == 3) { + for (int x = 0; x < _settings.range.getGlobalSize(0); x++) { + kernelState.setGlobalId(0, x); + + for (int y = 0; y < globalSize1; y++) { + kernelState.setGlobalId(1, y); + + for (int z = 0; z < _settings.range.getGlobalSize(2); z++) { + kernelState.setGlobalId(2, z); + kernelClone.run(); + } + + kernelClone.run(); + } + } + } + } + passId = PASS_ID_COMPLETED_EXECUTION; + } + else { + if (device != JavaDevice.THREAD_POOL && kernel.getExecutionMode() != Kernel.EXECUTION_MODE.JTP) { + throw new AssertionError("unexpected JavaDevice or EXECUTION_MODE"); + } + final int threads = localSize0 * localSize1 * localSize2; + final int numGroups0 = _settings.range.getNumGroups(0); + final int numGroups1 = _settings.range.getNumGroups(1); + final int globalGroups = numGroups0 * numGroups1 * _settings.range.getNumGroups(2); + /** + * This joinBarrier is the barrier that we provide for the kernel threads to rendezvous with the current dispatch thread. + * So this barrier is threadCount+1 wide (the +1 is for the dispatch thread) + */ + final CyclicBarrier joinBarrier = new FJSafeCyclicBarrier(threads + 1); + + /** + * This localBarrier is only ever used by the kernels. If the kernel does not use the barrier the threads + * can get out of sync, we promised nothing in JTP mode. + * + * As with OpenCL all threads within a group must wait at the barrier or none. It is a user error (possible deadlock!) + * if the barrier is in a conditional that is only executed by some of the threads within a group. + * + * Kernel developer must understand this. + * + * This barrier is threadCount wide. We never hit the barrier from the dispatch thread. + */ + final CyclicBarrier localBarrier = new FJSafeCyclicBarrier(threads); + + final ThreadIdSetter threadIdSetter; + + if (_settings.range.getDims() == 1) { + threadIdSetter = new ThreadIdSetter() { + @Override + public void set(KernelState kernelState, int globalGroupId, int threadId) { + // (kernelState, globalGroupId, threadId) ->{ + kernelState.setLocalId(0, (threadId % localSize0)); + kernelState.setGlobalId(0, (threadId + (globalGroupId * threads))); + kernelState.setGroupId(0, globalGroupId); + } + }; + } + else if (_settings.range.getDims() == 2) { + + /** + * Consider a 12x4 grid of 4*2 local groups + * <pre> + * threads = 4*2 = 8 + * localWidth=4 + * localHeight=2 + * globalWidth=12 + * globalHeight=4 + * + * 00 01 02 03 | 04 05 06 07 | 08 09 10 11 + * 12 13 14 15 | 16 17 18 19 | 20 21 22 23 + * ------------+-------------+------------ + * 24 25 26 27 | 28 29 30 31 | 32 33 34 35 + * 36 37 38 39 | 40 41 42 43 | 44 45 46 47 + * + * 00 01 02 03 | 00 01 02 03 | 00 01 02 03 threadIds : [0..7]*6 + * 04 05 06 07 | 04 05 06 07 | 04 05 06 07 + * ------------+-------------+------------ + * 00 01 02 03 | 00 01 02 03 | 00 01 02 03 + * 04 05 06 07 | 04 05 06 07 | 04 05 06 07 + * + * 00 00 00 00 | 01 01 01 01 | 02 02 02 02 groupId[0] : 0..6 + * 00 00 00 00 | 01 01 01 01 | 02 02 02 02 + * ------------+-------------+------------ + * 00 00 00 00 | 01 01 01 01 | 02 02 02 02 + * 00 00 00 00 | 01 01 01 01 | 02 02 02 02 + * + * 00 00 00 00 | 00 00 00 00 | 00 00 00 00 groupId[1] : 0..6 + * 00 00 00 00 | 00 00 00 00 | 00 00 00 00 + * ------------+-------------+------------ + * 01 01 01 01 | 01 01 01 01 | 01 01 01 01 + * 01 01 01 01 | 01 01 01 01 | 01 01 01 01 + * + * 00 01 02 03 | 08 09 10 11 | 16 17 18 19 globalThreadIds == threadId + groupId * threads; + * 04 05 06 07 | 12 13 14 15 | 20 21 22 23 + * ------------+-------------+------------ + * 24 25 26 27 | 32[33]34 35 | 40 41 42 43 + * 28 29 30 31 | 36 37 38 39 | 44 45 46 47 + * + * 00 01 02 03 | 00 01 02 03 | 00 01 02 03 localX = threadId % localWidth; (for globalThreadId 33 = threadId = 01 : 01%4 =1) + * 00 01 02 03 | 00 01 02 03 | 00 01 02 03 + * ------------+-------------+------------ + * 00 01 02 03 | 00[01]02 03 | 00 01 02 03 + * 00 01 02 03 | 00 01 02 03 | 00 01 02 03 + * + * 00 00 00 00 | 00 00 00 00 | 00 00 00 00 localY = threadId /localWidth (for globalThreadId 33 = threadId = 01 : 01/4 =0) + * 01 01 01 01 | 01 01 01 01 | 01 01 01 01 + * ------------+-------------+------------ + * 00 00 00 00 | 00[00]00 00 | 00 00 00 00 + * 01 01 01 01 | 01 01 01 01 | 01 01 01 01 + * + * 00 01 02 03 | 04 05 06 07 | 08 09 10 11 globalX= + * 00 01 02 03 | 04 05 06 07 | 08 09 10 11 groupsPerLineWidth=globalWidth/localWidth (=12/4 =3) + * ------------+-------------+------------ groupInset =groupId%groupsPerLineWidth (=4%3 = 1) + * 00 01 02 03 | 04[05]06 07 | 08 09 10 11 + * 00 01 02 03 | 04 05 06 07 | 08 09 10 11 globalX = groupInset*localWidth+localX (= 1*4+1 = 5) + * + * 00 00 00 00 | 00 00 00 00 | 00 00 00 00 globalY + * 01 01 01 01 | 01 01 01 01 | 01 01 01 01 + * ------------+-------------+------------ + * 02 02 02 02 | 02[02]02 02 | 02 02 02 02 + * 03 03 03 03 | 03 03 03 03 | 03 03 03 03 + * + * </pre> + * Assume we are trying to locate the id's for #33 + * + */ + threadIdSetter = new ThreadIdSetter() { + @Override + public void set(KernelState kernelState, int globalGroupId, int threadId) { + // (kernelState, globalGroupId, threadId) ->{ + kernelState.setLocalId(0, (threadId % localSize0)); // threadId % localWidth = (for 33 = 1 % 4 = 1) + kernelState.setLocalId(1, (threadId / localSize0)); // threadId / localWidth = (for 33 = 1 / 4 == 0) + + final int groupInset = globalGroupId % numGroups0; // 4%3 = 1 + kernelState.setGlobalId(0, ((groupInset * localSize0) + kernelState.getLocalIds()[0])); // 1*4+1=5 + + final int completeLines = (globalGroupId / numGroups0) * localSize1;// (4/3) * 2 + kernelState.setGlobalId(1, (completeLines + kernelState.getLocalIds()[1])); // 2+0 = 2 + kernelState.setGroupId(0, (globalGroupId % numGroups0)); + kernelState.setGroupId(1, (globalGroupId / numGroups0)); + } + }; + } + else if (_settings.range.getDims() == 3) { + //Same as 2D actually turns out that localId[0] is identical for all three dims so could be hoisted out of conditional code + threadIdSetter = new ThreadIdSetter() { + @Override + public void set(KernelState kernelState, int globalGroupId, int threadId) { + // (kernelState, globalGroupId, threadId) ->{ + kernelState.setLocalId(0, (threadId % localSize0)); + + kernelState.setLocalId(1, ((threadId / localSize0) % localSize1)); + + // the thread id's span WxHxD so threadId/(WxH) should yield the local depth + kernelState.setLocalId(2, (threadId / (localSize0 * localSize1))); + + kernelState.setGlobalId(0, (((globalGroupId % numGroups0) * localSize0) + kernelState.getLocalIds()[0])); + + kernelState.setGlobalId(1, + ((((globalGroupId / numGroups0) * localSize1) % globalSize1) + kernelState.getLocalIds()[1])); + + kernelState.setGlobalId(2, + (((globalGroupId / (numGroups0 * numGroups1)) * localSize2) + kernelState.getLocalIds()[2])); + + kernelState.setGroupId(0, (globalGroupId % numGroups0)); + kernelState.setGroupId(1, ((globalGroupId / numGroups0) % numGroups1)); + kernelState.setGroupId(2, (globalGroupId / (numGroups0 * numGroups1))); + } + }; + } + else + throw new IllegalArgumentException("Expected 1,2 or 3 dimensions, found " + _settings.range.getDims()); + for (passId = 0; passId < _settings.passes; passId++) { + if (getCancelState() == CANCEL_STATUS_TRUE) { + break; + } + /** + * Note that we emulate OpenCL by creating one thread per localId (across the group). + * + * So threadCount == range.getLocalSize(0)*range.getLocalSize(1)*range.getLocalSize(2); + * + * For a 1D range of 12 groups of 4 we create 4 threads. One per localId(0). + * + * We also clone the kernel 4 times. One per thread. + * + * We create local barrier which has a width of 4 + * + * Thread-0 handles localId(0) (global 0,4,8) + * Thread-1 handles localId(1) (global 1,5,7) + * Thread-2 handles localId(2) (global 2,6,10) + * Thread-3 handles localId(3) (global 3,7,11) + * + * This allows all threads to synchronize using the local barrier. + * + * Initially the use of local buffers seems broken as the buffers appears to be per Kernel. + * Thankfully Kernel.clone() performs a shallow clone of all buffers (local and global) + * So each of the cloned kernels actually still reference the same underlying local/global buffers. + * + * If the kernel uses local buffers but does not use barriers then it is possible for different groups + * to see mutations from each other (unlike OpenCL), however if the kernel does not us barriers then it + * cannot assume any coherence in OpenCL mode either (the failure mode will be different but still wrong) + * + * So even JTP mode use of local buffers will need to use barriers. Not for the same reason as OpenCL but to keep groups in lockstep. + * + **/ + for (int id = 0; id < threads; id++) { + final int threadId = id; + + /** + * We clone one kernel for each thread. + * + * They will all share references to the same range, localBarrier and global/local buffers because the clone is shallow. + * We need clones so that each thread can assign 'state' (localId/globalId/groupId) without worrying + * about other threads. + */ + final Kernel kernelClone = kernel.clone(); + final KernelState kernelState = kernelClone.getKernelState(); + kernelState.setRange(_settings.range); + kernelState.setPassId(passId); + + if (threads == 1) { + kernelState.disableLocalBarrier(); + } + else { + kernelState.setLocalBarrier(localBarrier); + } + + threadPool.submit( + // () -> { + new Runnable() { + public void run() { + try { + for (int globalGroupId = 0; globalGroupId < globalGroups; globalGroupId++) { + threadIdSetter.set(kernelState, globalGroupId, threadId); + kernelClone.run(); + } + } + catch (RuntimeException | Error e) { + logger.log(Level.SEVERE, "Execution failed", e); + } + finally { + await(joinBarrier); // This thread will rendezvous with dispatch thread here. This is effectively a join. + } + } + }); + } + + await(joinBarrier); // This dispatch thread waits for all worker threads here. + } + passId = PASS_ID_COMPLETED_EXECUTION; + } // execution mode == JTP + } + } finally { + passId = PASS_ID_COMPLETED_EXECUTION; + } + } + + private static void await(CyclicBarrier _barrier) { + try { + _barrier.await(); + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final BrokenBarrierException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private KernelArg[] args = null; + + private boolean usesOopConversion = false; + + /** + * + * @param arg + * @return + * @throws AparapiException + */ + private boolean prepareOopConversionBuffer(KernelArg arg) throws AparapiException { + usesOopConversion = true; + final Class<?> arrayClass = arg.getField().getType(); + ClassModel c = null; + boolean didReallocate = false; + + if (arg.getObjArrayElementModel() == null) { + final String tmp = arrayClass.getName().substring(2).replace('/', '.'); + final String arrayClassInDotForm = tmp.substring(0, tmp.length() - 1); + + if (logger.isLoggable(Level.FINE)) { + logger.fine("looking for type = " + arrayClassInDotForm); + } + + // get ClassModel of obj array from entrypt.objectArrayFieldsClasses + c = entryPoint.getObjectArrayFieldsClasses().get(arrayClassInDotForm); + arg.setObjArrayElementModel(c); + } else { + c = arg.getObjArrayElementModel(); + } + assert c != null : "should find class for elements " + arrayClass.getName(); + + final int arrayBaseOffset = UnsafeWrapper.arrayBaseOffset(arrayClass); + final int arrayScale = UnsafeWrapper.arrayIndexScale(arrayClass); + + if (logger.isLoggable(Level.FINEST)) { + logger.finest("Syncing obj array type = " + arrayClass + " cvtd= " + c.getClassWeAreModelling().getName() + + "arrayBaseOffset=" + arrayBaseOffset + " arrayScale=" + arrayScale); + } + + int objArraySize = 0; + Object newRef = null; + try { + newRef = arg.getField().get(kernel); + objArraySize = Array.getLength(newRef); + } catch (final IllegalAccessException e) { + throw new AparapiException(e); + } + + assert (newRef != null) && (objArraySize != 0) : "no data"; + + final int totalStructSize = c.getTotalStructSize(); + final int totalBufferSize = objArraySize * totalStructSize; + + // allocate ByteBuffer if first time or array changed + if ((arg.getObjArrayBuffer() == null) || (newRef != arg.getArray())) { + final ByteBuffer structBuffer = ByteBuffer.allocate(totalBufferSize); + arg.setObjArrayByteBuffer(structBuffer.order(ByteOrder.LITTLE_ENDIAN)); + arg.setObjArrayBuffer(arg.getObjArrayByteBuffer().array()); + didReallocate = true; + if (logger.isLoggable(Level.FINEST)) { + logger.finest("objArraySize = " + objArraySize + " totalStructSize= " + totalStructSize + " totalBufferSize=" + + totalBufferSize); + } + } else { + arg.getObjArrayByteBuffer().clear(); + } + + // copy the fields that the JNI uses + arg.setJavaArray(arg.getObjArrayBuffer()); + arg.setNumElements(objArraySize); + arg.setSizeInBytes(totalBufferSize); + + for (int j = 0; j < objArraySize; j++) { + int sizeWritten = 0; + + final Object object = UnsafeWrapper.getObject(newRef, arrayBaseOffset + (arrayScale * j)); + for (int i = 0; i < c.getStructMemberTypes().size(); i++) { + final TypeSpec t = c.getStructMemberTypes().get(i); + final long offset = c.getStructMemberOffsets().get(i); + + if (logger.isLoggable(Level.FINEST)) { + logger.finest("name = " + c.getStructMembers().get(i).getNameAndTypeEntry().getNameUTF8Entry().getUTF8() + " t= " + + t); + } + + switch (t) { + case I: { + final int x = UnsafeWrapper.getInt(object, offset); + arg.getObjArrayByteBuffer().putInt(x); + sizeWritten += t.getSize(); + break; + } + case F: { + final float x = UnsafeWrapper.getFloat(object, offset); + arg.getObjArrayByteBuffer().putFloat(x); + sizeWritten += t.getSize(); + break; + } + case J: { + final long x = UnsafeWrapper.getLong(object, offset); + arg.getObjArrayByteBuffer().putLong(x); + sizeWritten += t.getSize(); + break; + } + case Z: { + final boolean x = UnsafeWrapper.getBoolean(object, offset); + arg.getObjArrayByteBuffer().put(x == true ? (byte) 1 : (byte) 0); + // Booleans converted to 1 byte C chars for opencl + sizeWritten += TypeSpec.B.getSize(); + break; + } + case B: { + final byte x = UnsafeWrapper.getByte(object, offset); + arg.getObjArrayByteBuffer().put(x); + sizeWritten += t.getSize(); + break; + } + case D: { + throw new AparapiException("Double not implemented yet"); + } + default: + assert true == false : "typespec did not match anything"; + throw new AparapiException("Unhandled type in buffer conversion"); + } + } + + // add padding here if needed + if (logger.isLoggable(Level.FINEST)) { + logger.finest("sizeWritten = " + sizeWritten + " totalStructSize= " + totalStructSize); + } + + assert sizeWritten <= totalStructSize : "wrote too much into buffer"; + + while (sizeWritten < totalStructSize) { + if (logger.isLoggable(Level.FINEST)) { + logger.finest(arg.getName() + " struct pad byte = " + sizeWritten + " totalStructSize= " + totalStructSize); + } + arg.getObjArrayByteBuffer().put((byte) -1); + sizeWritten++; + } + } + + assert arg.getObjArrayByteBuffer().arrayOffset() == 0 : "should be zero"; + + return didReallocate; + } + + private void extractOopConversionBuffer(KernelArg arg) throws AparapiException { + final Class<?> arrayClass = arg.getField().getType(); + final ClassModel c = arg.getObjArrayElementModel(); + assert c != null : "should find class for elements: " + arrayClass.getName(); + assert arg.getArray() != null : "array is null"; + + final int arrayBaseOffset = UnsafeWrapper.arrayBaseOffset(arrayClass); + final int arrayScale = UnsafeWrapper.arrayIndexScale(arrayClass); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("Syncing field:" + arg.getName() + ", bb=" + arg.getObjArrayByteBuffer() + ", type = " + arrayClass); + } + + int objArraySize = 0; + try { + objArraySize = Array.getLength(arg.getField().get(kernel)); + } catch (final IllegalAccessException e) { + throw new AparapiException(e); + } + + assert objArraySize > 0 : "should be > 0"; + + final int totalStructSize = c.getTotalStructSize(); + // int totalBufferSize = objArraySize * totalStructSize; + // assert arg.objArrayBuffer.length == totalBufferSize : "size should match"; + + arg.getObjArrayByteBuffer().rewind(); + + for (int j = 0; j < objArraySize; j++) { + int sizeWritten = 0; + final Object object = UnsafeWrapper.getObject(arg.getArray(), arrayBaseOffset + (arrayScale * j)); + for (int i = 0; i < c.getStructMemberTypes().size(); i++) { + final TypeSpec t = c.getStructMemberTypes().get(i); + final long offset = c.getStructMemberOffsets().get(i); + switch (t) { + case I: { + // read int value from buffer and store into obj in the array + final int x = arg.getObjArrayByteBuffer().getInt(); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("fType = " + t.getShortName() + " x= " + x); + } + UnsafeWrapper.putInt(object, offset, x); + sizeWritten += t.getSize(); + break; + } + case F: { + final float x = arg.getObjArrayByteBuffer().getFloat(); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("fType = " + t.getShortName() + " x= " + x); + } + UnsafeWrapper.putFloat(object, offset, x); + sizeWritten += t.getSize(); + break; + } + case J: { + final long x = arg.getObjArrayByteBuffer().getLong(); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("fType = " + t.getShortName() + " x= " + x); + } + UnsafeWrapper.putLong(object, offset, x); + sizeWritten += t.getSize(); + break; + } + case Z: { + final byte x = arg.getObjArrayByteBuffer().get(); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("fType = " + t.getShortName() + " x= " + x); + } + UnsafeWrapper.putBoolean(object, offset, (x == 1 ? true : false)); + // Booleans converted to 1 byte C chars for open cl + sizeWritten += TypeSpec.B.getSize(); + break; + } + case B: { + final byte x = arg.getObjArrayByteBuffer().get(); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("fType = " + t.getShortName() + " x= " + x); + } + UnsafeWrapper.putByte(object, offset, x); + sizeWritten += t.getSize(); + break; + } + case D: { + throw new AparapiException("Double not implemented yet"); + } + default: + assert true == false : "typespec did not match anything"; + throw new AparapiException("Unhandled type in buffer conversion"); + } + } + + // add padding here if needed + if (logger.isLoggable(Level.FINEST)) { + logger.finest("sizeWritten = " + sizeWritten + " totalStructSize= " + totalStructSize); + } + + assert sizeWritten <= totalStructSize : "wrote too much into buffer"; + + while (sizeWritten < totalStructSize) { + // skip over pad bytes + arg.getObjArrayByteBuffer().get(); + sizeWritten++; + } + } + } + + private void restoreObjects() throws AparapiException { + for (int i = 0; i < argc; i++) { + final KernelArg arg = args[i]; + if ((arg.getType() & ARG_OBJ_ARRAY_STRUCT) != 0) { + extractOopConversionBuffer(arg); + } + } + } + + private boolean updateKernelArrayRefs() throws AparapiException { + boolean needsSync = false; + + for (int i = 0; i < argc; i++) { + final KernelArg arg = args[i]; + try { + if ((arg.getType() & ARG_ARRAY) != 0) { + Object newArrayRef; + newArrayRef = arg.getField().get(kernel); + + if (newArrayRef == null) { + throw new IllegalStateException("Cannot send null refs to kernel, reverting to java"); + } + + String fieldName = arg.getField().getName(); + int arrayLength = Array.getLength(newArrayRef); + Integer privateMemorySize = ClassModel.getPrivateMemorySizeFromField(arg.getField()); + if (privateMemorySize == null) { + privateMemorySize = ClassModel.getPrivateMemorySizeFromFieldName(fieldName); + } + if (privateMemorySize != null) { + if (arrayLength > privateMemorySize) { + throw new IllegalStateException("__private array field " + fieldName + " has illegal length " + arrayLength + + " > " + privateMemorySize); + } + } + + if ((arg.getType() & ARG_OBJ_ARRAY_STRUCT) != 0) { + prepareOopConversionBuffer(arg); + } else { + // set up JNI fields for normal arrays + arg.setJavaArray(newArrayRef); + arg.setNumElements(arrayLength); + arg.setSizeInBytes(arg.getNumElements() * arg.getPrimitiveSize()); + + if (((args[i].getType() & ARG_EXPLICIT) != 0) && puts.contains(newArrayRef)) { + args[i].setType(args[i].getType() | ARG_EXPLICIT_WRITE); + // System.out.println("detected an explicit write " + args[i].name); + puts.remove(newArrayRef); + } + } + + if (newArrayRef != arg.getArray()) { + needsSync = true; + + if (logger.isLoggable(Level.FINE)) { + logger.fine("saw newArrayRef for " + arg.getName() + " = " + newArrayRef + ", newArrayLen = " + + Array.getLength(newArrayRef)); + } + } + + arg.setArray(newArrayRef); + assert arg.getArray() != null : "null array ref"; + } else if ((arg.getType() & ARG_APARAPI_BUFFER) != 0) { + // TODO: check if the 2D/3D array is changed. + // can Arrays.equals help? + needsSync = true; // Always need syn + Object buffer = new Object(); + try { + buffer = arg.getField().get(kernel); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + int numDims = arg.getNumDims(); + Object subBuffer = buffer; + int[] dims = new int[numDims]; + for (int d = 0; d < numDims - 1; d++) { + dims[d] = Array.getLength(subBuffer); + subBuffer = Array.get(subBuffer, 0); + } + dims[numDims - 1] = Array.getLength(subBuffer); + arg.setDims(dims); + + int primitiveSize = getPrimitiveSize(arg.getType()); + int totalElements = 1; + for (int d = 0; d < numDims; d++) { + totalElements *= dims[d]; + } + arg.setJavaBuffer(buffer); + arg.setSizeInBytes(totalElements * primitiveSize); + arg.setArray(buffer); + } + } catch (final IllegalArgumentException e) { + e.printStackTrace(); + } catch (final IllegalAccessException e) { + e.printStackTrace(); + } + } + return needsSync; + } + + @SuppressWarnings("deprecation") + private Kernel executeOpenCL(ExecutionSettings _settings) throws AparapiException { + + // Read the array refs after kernel may have changed them + // We need to do this as input to computing the localSize + assert args != null : "args should not be null"; + final boolean needSync = updateKernelArrayRefs(); + if (needSync && logger.isLoggable(Level.FINE)) { + logger.fine("Need to resync arrays on " + kernel); + } + + // native side will reallocate array buffers if necessary + int returnValue = runKernelJNI(jniContextHandle, _settings.range, needSync, _settings.passes, inBufferRemote, outBufferRemote); + if (returnValue != 0) { + String reason = "OpenCL execution seems to have failed (runKernelJNI returned " + returnValue + ")"; + return fallBackToNextDevice(_settings, new AparapiException(reason)); + } + + if (usesOopConversion == true) { + restoreObjects(); + } + + if (logger.isLoggable(Level.FINE)) { + logger.fine("executeOpenCL completed. " + _settings.range); + } + + return kernel; + } + + @SuppressWarnings("deprecation") + synchronized private Kernel fallBackByExecutionMode(ExecutionSettings _settings) { + isFallBack = true; + if (kernel.hasNextExecutionMode()) { + kernel.tryNextExecutionMode(); + if (logger.isLoggable(Level.WARNING)) { + logger.warning("Trying next execution mode " + kernel.getExecutionMode()); + } + } else { + kernel.setFallbackExecutionMode(); + } + recreateRange(_settings); + return executeInternalInner(_settings); + } + + private void recreateRange(ExecutionSettings _settings) { + if (_settings.range.isLocalIsDerived() && !_settings.legacyExecutionMode) { + Device device = kernel.getTargetDevice(); + Range result; + switch (_settings.range.getDims()) { + case 1: { + result = Range.create(device, _settings.range.getGlobalSize_0()); + break; + } + case 2: { + result = Range.create2D(device, _settings.range.getGlobalSize_0(), _settings.range.getGlobalSize_1()); + break; + } + case 3: { + result = Range.create3D(device, _settings.range.getGlobalSize_0(), _settings.range.getGlobalSize_1(), _settings.range.getGlobalSize_2()); + break; + } + default: { + throw new AssertionError("Range.getDims() = " + _settings.range.getDims()); + } + } + _settings.range = result; + } + } + + private Kernel fallBackToNextDevice(ExecutionSettings _settings, String _reason) { + return fallBackToNextDevice(_settings, new AparapiException(_reason)); + } + + @SuppressWarnings("deprecation") + synchronized private Kernel fallBackToNextDevice(ExecutionSettings _settings, Exception _exception) { + return fallBackToNextDevice(_settings, _exception, false); + } + + @SuppressWarnings("deprecation") + synchronized private Kernel fallBackToNextDevice(ExecutionSettings _settings, Exception _exception, boolean _silently) { + isFallBack = true; + _settings.profile.onEvent(ProfilingEvent.EXECUTED); + if (_settings.legacyExecutionMode) { + if (!_silently && logger.isLoggable(Level.WARNING)) { + logger.warning("Execution mode " + kernel.getExecutionMode() + " failed for " + kernel + ": " + _exception.getMessage()); + _exception.printStackTrace(); + } + return fallBackByExecutionMode(_settings); + } else { + KernelPreferences preferences = KernelManager.instance().getPreferences(kernel); + if (!_silently && logger.isLoggable(Level.WARNING)) { + logger.warning("Device failed for " + kernel + ": " + _exception.getMessage()); + } + + preferences.markPreferredDeviceFailed(); + +// Device nextDevice = preferences.getPreferredDevice(kernel); +// +// if (nextDevice == null) { +// if (!_silently && logger.isLoggable(Level.SEVERE)) { +// logger.severe("No Devices left to try, giving up"); +// } +// throw new RuntimeException(_exception); +// } + if (!_silently && logger.isLoggable(Level.WARNING)) { + _exception.printStackTrace(); + logger.warning("Trying next device: " + describeDevice()); + } + } + + recreateRange(_settings); + return executeInternalInner(_settings); + } + + @SuppressWarnings("deprecation") + public synchronized Kernel execute(String _entrypoint, final Range _range, final int _passes) { + executing = true; + try { + clearCancelMultiPass(); + KernelProfile profile = KernelManager.instance().getProfile(kernel.getClass()); + KernelPreferences preferences = KernelManager.instance().getPreferences(kernel); + boolean legacyExecutionMode = kernel.getExecutionMode() != Kernel.EXECUTION_MODE.AUTO; + + ExecutionSettings settings = new ExecutionSettings(preferences, profile, _entrypoint, _range, _passes, legacyExecutionMode); + // Two Kernels of the same class share the same KernelPreferences object, and since failure (fallback) generally mutates + // the preferences object, we must lock it. Note this prevents two Kernels of the same class executing simultaneously. + synchronized (preferences) { + return executeInternalOuter(settings); + } + } finally { + executing = false; + clearCancelMultiPass(); + } + } + + private synchronized Kernel executeInternalOuter(ExecutionSettings _settings) { + try { + return executeInternalInner(_settings); + } finally { + if (kernel.isAutoCleanUpArrays() &&_settings.range.getGlobalSize_0() != 0) { + cleanUpArrays(); + } + } + } + + @SuppressWarnings("deprecation") + private synchronized Kernel executeInternalInner(ExecutionSettings _settings) { + + if (_settings.range == null) { + throw new IllegalStateException("range can't be null"); + } + + EXECUTION_MODE requestedExecutionMode = kernel.getExecutionMode(); + + if (requestedExecutionMode.isOpenCL() && _settings.range.getDevice() != null && !(_settings.range.getDevice() instanceof OpenCLDevice)) { + fallBackToNextDevice(_settings, "OpenCL EXECUTION_MODE was requested but Device supplied was not an OpenCLDevice"); + } + + Device device = _settings.range.getDevice(); + boolean userSpecifiedDevice = true; + if (device == null) { + userSpecifiedDevice = false; + if (!_settings.legacyExecutionMode) { + device = _settings.preferences.getPreferredDevice(kernel); + if (device == null) { + // the default fallback when KernelPreferences has run out of options is JTP + device = JavaDevice.THREAD_POOL; + } + } else { + if (requestedExecutionMode == EXECUTION_MODE.JTP) { + device = JavaDevice.THREAD_POOL; + } else if (requestedExecutionMode == EXECUTION_MODE.SEQ) { + device = JavaDevice.SEQUENTIAL; + } + } + } else { + boolean compatible = isDeviceCompatible(device); + if (!compatible) { + throw new AssertionError("user supplied Device incompatible with current EXECUTION_MODE or getTargetDevice(); device = " + + device.getShortDescription() + "; kernel = " + kernel); + } + } + + try { + OpenCLDevice openCLDevice = device instanceof OpenCLDevice ? (OpenCLDevice) device : null; + + int jniFlags = 0; + // for legacy reasons use old logic where Kernel.EXECUTION_MODE is not AUTO + if (_settings.legacyExecutionMode && !userSpecifiedDevice && requestedExecutionMode.isOpenCL()) { + if (requestedExecutionMode.equals(EXECUTION_MODE.GPU)) { + // Get the best GPU + openCLDevice = (OpenCLDevice) KernelManager.DeprecatedMethods.bestGPU(); + jniFlags |= JNI_FLAG_USE_GPU; // this flag might be redundant now. + if (openCLDevice == null) { + return fallBackToNextDevice(_settings, "GPU request can't be honored, no GPU device"); + } + } else if (requestedExecutionMode.equals(EXECUTION_MODE.ACC)) { + // Get the best ACC + openCLDevice = (OpenCLDevice) KernelManager.DeprecatedMethods.bestACC(); + jniFlags |= JNI_FLAG_USE_ACC; // this flag might be redundant now. + if (openCLDevice == null) { + return fallBackToNextDevice(_settings, "ACC request can't be honored, no ACC device"); + } + } else { + // We fetch the first CPU device + openCLDevice = (OpenCLDevice) KernelManager.DeprecatedMethods.firstDevice(Device.TYPE.CPU); + if (openCLDevice == null) { + return fallBackToNextDevice(_settings, "CPU request can't be honored, no CPU device"); + } + } + } else { + if (device.getType() == Device.TYPE.GPU) { + jniFlags |= JNI_FLAG_USE_GPU; // this flag might be redundant now. + } else if (device.getType() == Device.TYPE.ACC) { + jniFlags |= JNI_FLAG_USE_ACC; // this flag might be redundant now. + } + } + if (device == null && openCLDevice != null) { + device = openCLDevice; + } + assert device != null : "No device available"; + _settings.profile.onStart(device); + /* for backward compatibility reasons we still honor execution mode */ + boolean isOpenCl = requestedExecutionMode.isOpenCL() || device instanceof OpenCLDevice; + if (isOpenCl) { + if ((entryPoint == null) || (isFallBack)) { + if (entryPoint == null) { + try { + final ClassModel classModel = ClassModel.createClassModel(kernel.getClass()); + entryPoint = classModel.getEntrypoint(_settings.entrypoint, kernel); + _settings.profile.onEvent(ProfilingEvent.CLASS_MODEL_BUILT); + } catch (final Exception exception) { + _settings.profile.onEvent(ProfilingEvent.CLASS_MODEL_BUILT); + return fallBackToNextDevice(_settings, exception); + } + } + + if ((entryPoint != null)) { + synchronized (Kernel.class) { // This seems to be needed because of a race condition uncovered with issue #68 http://code.google.com/p/aparapi/issues/detail?id=68 + + // jniFlags |= (Config.enableProfiling ? JNI_FLAG_ENABLE_PROFILING : 0); + // jniFlags |= (Config.enableProfilingCSV ? JNI_FLAG_ENABLE_PROFILING_CSV | JNI_FLAG_ENABLE_PROFILING : 0); + // jniFlags |= (Config.enableVerboseJNI ? JNI_FLAG_ENABLE_VERBOSE_JNI : 0); + // jniFlags |= (Config.enableVerboseJNIOpenCLResourceTracking ? JNI_FLAG_ENABLE_VERBOSE_JNI_OPENCL_RESOURCE_TRACKING :0); + // jniFlags |= (kernel.getExecutionMode().equals(Kernel.EXECUTION_MODE.GPU) ? JNI_FLAG_USE_GPU : 0); + // Init the device to check capabilities before emitting the + // code that requires the capabilities. + jniContextHandle = initJNI(kernel, openCLDevice, jniFlags); // openCLDevice will not be null here + _settings.profile.onEvent(ProfilingEvent.INIT_JNI); + } // end of synchronized! issue 68 + + if (jniContextHandle == 0) { + return fallBackToNextDevice(_settings, "initJNI failed to return a valid handle"); + } + + final String extensions = getExtensionsJNI(jniContextHandle); + capabilitiesSet = new HashSet<String>(); + + final StringTokenizer strTok = new StringTokenizer(extensions); + while (strTok.hasMoreTokens()) { + capabilitiesSet.add(strTok.nextToken()); + } + + if (logger.isLoggable(Level.FINE)) { + logger.fine("Capabilities initialized to :" + capabilitiesSet.toString()); + } + + if (entryPoint.requiresDoublePragma() && !hasFP64Support()) { + return fallBackToNextDevice(_settings, "FP64 required but not supported"); + } + + if (entryPoint.requiresByteAddressableStorePragma() && !hasByteAddressableStoreSupport()) { + return fallBackToNextDevice(_settings, "Byte addressable stores required but not supported"); + } + + final boolean all32AtomicsAvailable = hasGlobalInt32BaseAtomicsSupport() + && hasGlobalInt32ExtendedAtomicsSupport() && hasLocalInt32BaseAtomicsSupport() + && hasLocalInt32ExtendedAtomicsSupport(); + + if (entryPoint.requiresAtomic32Pragma() && !all32AtomicsAvailable) { + + return fallBackToNextDevice(_settings, "32 bit Atomics required but not supported"); + } + + String openCL; + synchronized (openCLCache) { + openCL = openCLCache.get(kernel.getClass()); + if (openCL == null) { + try { + openCL = KernelWriter.writeToString(entryPoint); + if (logger.isLoggable(Level.INFO)) { + logger.info(openCL); + } + else if (Config.enableShowGeneratedOpenCL) { + System.out.println(openCL); + } + _settings.profile.onEvent(ProfilingEvent.OPENCL_GENERATED); + openCLCache.put(kernel.getClass(), openCL); + } + catch (final CodeGenException codeGenException) { + openCLCache.put(kernel.getClass(), CODE_GEN_ERROR_MARKER); + _settings.profile.onEvent(ProfilingEvent.OPENCL_GENERATED); + return fallBackToNextDevice(_settings, codeGenException); + } + } + else { + if (openCL.equals(CODE_GEN_ERROR_MARKER)) { + _settings.profile.onEvent(ProfilingEvent.OPENCL_GENERATED); + boolean silently = true; // since we must have already reported the CodeGenException + return fallBackToNextDevice(_settings, null, silently); + } + } + } + + // Send the string to OpenCL to compile it, or if the compiled binary is already cached on JNI side just empty string to use cached binary + long handle; + if (BINARY_CACHING_DISABLED) { + handle = buildProgramJNI(jniContextHandle, openCL, ""); + } else { + synchronized (seenBinaryKeys) { + String binaryKey = kernel.getClass().getName() + ":" + device.getDeviceId(); + if (seenBinaryKeys.contains(binaryKey)) { + // use cached binary + logger.log(Level.INFO, "reusing cached binary for " + binaryKey); + handle = buildProgramJNI(jniContextHandle, "", binaryKey); + } + else { + // create and cache binary + logger.log(Level.INFO, "compiling new binary for " + binaryKey); + handle = buildProgramJNI(jniContextHandle, openCL, binaryKey); + seenBinaryKeys.add(binaryKey); + } + } + } + _settings.profile.onEvent(ProfilingEvent.OPENCL_COMPILED); + if (handle == 0) { + return fallBackToNextDevice(_settings, "OpenCL compile failed"); + } + + args = new KernelArg[entryPoint.getReferencedFields().size()]; + int i = 0; + + for (final Field field : entryPoint.getReferencedFields()) { + try { + field.setAccessible(true); + args[i] = new KernelArg(); + args[i].setName(field.getName()); + args[i].setField(field); + if ((field.getModifiers() & Modifier.STATIC) == Modifier.STATIC) { + args[i].setType(args[i].getType() | ARG_STATIC); + } + + final Class<?> type = field.getType(); + if (type.isArray()) { + + if (field.getAnnotation(Local.class) != null || args[i].getName().endsWith(Kernel.LOCAL_SUFFIX)) { + args[i].setType(args[i].getType() | ARG_LOCAL); + } else if ((field.getAnnotation(Constant.class) != null) + || args[i].getName().endsWith(Kernel.CONSTANT_SUFFIX)) { + args[i].setType(args[i].getType() | ARG_CONSTANT); + } else { + args[i].setType(args[i].getType() | ARG_GLOBAL); + } + if (isExplicit()) { + args[i].setType(args[i].getType() | ARG_EXPLICIT); + } + // for now, treat all write arrays as read-write, see bugzilla issue 4859 + // we might come up with a better solution later + args[i].setType(args[i].getType() + | (entryPoint.getArrayFieldAssignments().contains(field.getName()) ? (ARG_WRITE | ARG_READ) : 0)); + args[i].setType(args[i].getType() + | (entryPoint.getArrayFieldAccesses().contains(field.getName()) ? ARG_READ : 0)); + // args[i].type |= ARG_GLOBAL; + + if (type.getName().startsWith("[L")) { + args[i].setArray(null); // will get updated in updateKernelArrayRefs + args[i].setType(args[i].getType() + | (ARG_ARRAY | ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)); + + if (logger.isLoggable(Level.FINE)) { + logger.fine("tagging " + args[i].getName() + " as (ARG_ARRAY | ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)"); + } + } else if (type.getName().startsWith("[[")) { + + try { + setMultiArrayType(args[i], type); + } catch (AparapiException e) { + return fallBackToNextDevice(_settings, "failed to set kernel arguement " + + args[i].getName() + ". Aparapi only supports 2D and 3D arrays."); + } + } else { + + args[i].setArray(null); // will get updated in updateKernelArrayRefs + args[i].setType(args[i].getType() | ARG_ARRAY); + + args[i].setType(args[i].getType() | (type.isAssignableFrom(float[].class) ? ARG_FLOAT : 0)); + args[i].setType(args[i].getType() | (type.isAssignableFrom(int[].class) ? ARG_INT : 0)); + args[i].setType(args[i].getType() | (type.isAssignableFrom(boolean[].class) ? ARG_BOOLEAN : 0)); + args[i].setType(args[i].getType() | (type.isAssignableFrom(byte[].class) ? ARG_BYTE : 0)); + args[i].setType(args[i].getType() | (type.isAssignableFrom(char[].class) ? ARG_CHAR : 0)); + args[i].setType(args[i].getType() | (type.isAssignableFrom(double[].class) ? ARG_DOUBLE : 0)); + args[i].setType(args[i].getType() | (type.isAssignableFrom(long[].class) ? ARG_LONG : 0)); + args[i].setType(args[i].getType() | (type.isAssignableFrom(short[].class) ? ARG_SHORT : 0)); + + // arrays whose length is used will have an int arg holding + // the length as a kernel param + if (entryPoint.getArrayFieldArrayLengthUsed().contains(args[i].getName())) { + args[i].setType(args[i].getType() | ARG_ARRAYLENGTH); + } + + if (type.getName().startsWith("[L")) { + args[i].setType(args[i].getType() | (ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)); + if (logger.isLoggable(Level.FINE)) { + logger.fine("tagging " + args[i].getName() + + " as (ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)"); + } + } + } + } else if (type.isAssignableFrom(float.class)) { + args[i].setType(args[i].getType() | ARG_PRIMITIVE); + args[i].setType(args[i].getType() | ARG_FLOAT); + } else if (type.isAssignableFrom(int.class)) { + args[i].setType(args[i].getType() | ARG_PRIMITIVE); + args[i].setType(args[i].getType() | ARG_INT); + } else if (type.isAssignableFrom(double.class)) { + args[i].setType(args[i].getType() | ARG_PRIMITIVE); + args[i].setType(args[i].getType() | ARG_DOUBLE); + } else if (type.isAssignableFrom(long.class)) { + args[i].setType(args[i].getType() | ARG_PRIMITIVE); + args[i].setType(args[i].getType() | ARG_LONG); + } else if (type.isAssignableFrom(boolean.class)) { + args[i].setType(args[i].getType() | ARG_PRIMITIVE); + args[i].setType(args[i].getType() | ARG_BOOLEAN); + } else if (type.isAssignableFrom(byte.class)) { + args[i].setType(args[i].getType() | ARG_PRIMITIVE); + args[i].setType(args[i].getType() | ARG_BYTE); + } else if (type.isAssignableFrom(char.class)) { + args[i].setType(args[i].getType() | ARG_PRIMITIVE); + args[i].setType(args[i].getType() | ARG_CHAR); + } else if (type.isAssignableFrom(short.class)) { + args[i].setType(args[i].getType() | ARG_PRIMITIVE); + args[i].setType(args[i].getType() | ARG_SHORT); + } + // System.out.printf("in execute, arg %d %s %08x\n", i,args[i].name,args[i].type ); + } catch (final IllegalArgumentException e) { + e.printStackTrace(); + } + + args[i].setPrimitiveSize(getPrimitiveSize(args[i].getType())); + + if (logger.isLoggable(Level.FINE)) { + logger.fine("arg " + i + ", " + args[i].getName() + ", type=" + Integer.toHexString(args[i].getType()) + + ", primitiveSize=" + args[i].getPrimitiveSize()); + } + + i++; + } + + // at this point, i = the actual used number of arguments + // (private buffers do not get treated as arguments) + + argc = i; + + setArgsJNI(jniContextHandle, args, argc); + _settings.profile.onEvent(ProfilingEvent.PREPARE_EXECUTE); + try { + executeOpenCL(_settings); + isFallBack = false; + } catch (final AparapiException e) { + fallBackToNextDevice(_settings, e); + } + } else { // (entryPoint != null) && !entryPoint.shouldFallback() + fallBackToNextDevice(_settings, "failed to locate entrypoint"); + } + } else { // (entryPoint == null) || (isFallBack) + try { + executeOpenCL(_settings); + isFallBack = false; + } catch (final AparapiException e) { + fallBackToNextDevice(_settings, e); + } + } + } else { // isOpenCL + if (!(device instanceof JavaDevice)) { + fallBackToNextDevice(_settings, "Non-OpenCL Kernel.EXECUTION_MODE requested but device is not a JavaDevice "); + } + executeJava(_settings, (JavaDevice) device); + } + + if (Config.enableExecutionModeReporting) { + System.out.println("execution complete: " + kernel); + } + + return kernel; + } + finally { + _settings.profile.onEvent(ProfilingEvent.EXECUTED); + maybeReportProfile(_settings); + } + } + + @Override + public String toString() { + return "KernelRunner{" + kernel + "}"; + } + + private String describeDevice() { + Device device = KernelManager.instance().getPreferences(kernel).getPreferredDevice(kernel); + return (device == null) ? "<default fallback>" : device.getShortDescription(); + } + + private void maybeReportProfile(ExecutionSettings _settings) { + if (Config.dumpProfileOnExecution) { + StringBuilder report = new StringBuilder(); + report.append(KernelDeviceProfile.getTableHeader()).append('\n'); + report.append(_settings.profile.getLastDeviceProfile().getLastAsTableRow()); + System.out.println(report); + } + } + + @SuppressWarnings("deprecation") + private boolean isDeviceCompatible(Device device) { + Kernel.EXECUTION_MODE mode = kernel.getExecutionMode(); + if (mode != Kernel.EXECUTION_MODE.AUTO) { + switch (device.getType()) { + case GPU: + return mode == Kernel.EXECUTION_MODE.GPU; + case CPU: + return mode == Kernel.EXECUTION_MODE.CPU; + case JTP: + return mode == Kernel.EXECUTION_MODE.JTP; + case SEQ: + return mode == Kernel.EXECUTION_MODE.SEQ; + case ACC: + return mode == Kernel.EXECUTION_MODE.ACC; + default: + return false; + } + } else { + return (device == kernel.getTargetDevice()); + } + } + + public int getCancelState() { + return inBufferRemoteInt.get(0); + } + + public void cancelMultiPass() { + inBufferRemoteInt.put(0, CANCEL_STATUS_TRUE); + } + + private void clearCancelMultiPass() { + inBufferRemoteInt.put(0, CANCEL_STATUS_FALSE); + } + + /** + * Returns the index of the current pass, or one of two special constants with negative values to indicate special progress states. Those constants are + * {@link #PASS_ID_PREPARING_EXECUTION} to indicate that the Kernel has started executing but not reached the initial pass, or + * {@link #PASS_ID_COMPLETED_EXECUTION} to indicate that execution is complete (possibly due to early termination via {@link #cancelMultiPass()}), i.e. the Kernel + * is idle. {@link #PASS_ID_COMPLETED_EXECUTION} is also returned before the first execution has been invoked. + * + * <p>This can be used, for instance, to update a visual progress bar. + * + * @see #execute(String, Range, int) + */ + public int getCurrentPass() { + if (!executing) { + return PASS_ID_COMPLETED_EXECUTION; + } + + if (kernel.isRunningCL()) { + return getCurrentPassRemote(); + } else { + return getCurrentPassLocal(); + } + } + + /** + * True while any of the {@code execute()} methods are in progress. + */ + public boolean isExecuting() { + return executing; + } + + protected int getCurrentPassRemote() { + return outBufferRemoteInt.get(0); + } + + private int getCurrentPassLocal() { + return passId; + } + + private int getPrimitiveSize(int type) { + if ((type & ARG_FLOAT) != 0) { + return 4; + } else if ((type & ARG_INT) != 0) { + return 4; + } else if ((type & ARG_BYTE) != 0) { + return 1; + } else if ((type & ARG_CHAR) != 0) { + return 2; + } else if ((type & ARG_BOOLEAN) != 0) { + return 1; + } else if ((type & ARG_SHORT) != 0) { + return 2; + } else if ((type & ARG_LONG) != 0) { + return 8; + } else if ((type & ARG_DOUBLE) != 0) { + return 8; + } + return 0; + } + + private void setMultiArrayType(KernelArg arg, Class<?> type) throws AparapiException { + arg.setType(arg.getType() | (ARG_WRITE | ARG_READ | ARG_APARAPI_BUFFER)); + int numDims = 0; + while (type.getName().startsWith("[[[[")) { + throw new AparapiException("Aparapi only supports 2D and 3D arrays."); + } + arg.setType(arg.getType() | ARG_ARRAYLENGTH); + while (type.getName().charAt(numDims) == '[') { + numDims++; + } + arg.setNumDims(numDims); + arg.setJavaBuffer(null); // will get updated in updateKernelArrayRefs + arg.setArray(null); // will get updated in updateKernelArrayRefs + + Class<?> elementType = arg.getField().getType(); + while (elementType.isArray()) { + elementType = elementType.getComponentType(); + } + + if (elementType.isAssignableFrom(float.class)) { + arg.setType(arg.getType() | ARG_FLOAT); + } else if (elementType.isAssignableFrom(int.class)) { + arg.setType(arg.getType() | ARG_INT); + } else if (elementType.isAssignableFrom(boolean.class)) { + arg.setType(arg.getType() | ARG_BOOLEAN); + } else if (elementType.isAssignableFrom(byte.class)) { + arg.setType(arg.getType() | ARG_BYTE); + } else if (elementType.isAssignableFrom(char.class)) { + arg.setType(arg.getType() | ARG_CHAR); + } else if (elementType.isAssignableFrom(double.class)) { + arg.setType(arg.getType() | ARG_DOUBLE); + } else if (elementType.isAssignableFrom(long.class)) { + arg.setType(arg.getType() | ARG_LONG); + } else if (elementType.isAssignableFrom(short.class)) { + arg.setType(arg.getType() | ARG_SHORT); + } + } + + private final Set<Object> puts = new HashSet<Object>(); + + /** + * Enqueue a request to return this array from the GPU. This method blocks until the array is available. + * <br/> + * Note that <code>Kernel.put(type [])</code> calls will delegate to this call. + * <br/> + * Package public + * + * @param array + * It is assumed that this parameter is indeed an array (of int, float, short etc). + * + * @see Kernel#get(int[] arr) + * @see Kernel#get(float[] arr) + * @see Kernel#get(double[] arr) + * @see Kernel#get(long[] arr) + * @see Kernel#get(char[] arr) + * @see Kernel#get(boolean[] arr) + */ + public void get(Object array) { + if (explicit && (kernel.isRunningCL())) { + // Only makes sense when we are using OpenCL + getJNI(jniContextHandle, array); + } + } + + public List<ProfileInfo> getProfileInfo() { + if (explicit && (kernel.isRunningCL())) { + // Only makes sense when we are using OpenCL + return (getProfileInfoJNI(jniContextHandle)); + } else { + return (null); + } + } + + /** + * Tag this array so that it is explicitly enqueued before the kernel is executed. <br/> + * Note that <code>Kernel.put(type [])</code> calls will delegate to this call. <br/> + * Package public + * + * @param array + * It is assumed that this parameter is indeed an array (of int, float, short etc). + * @see Kernel#put(int[] arr) + * @see Kernel#put(float[] arr) + * @see Kernel#put(double[] arr) + * @see Kernel#put(long[] arr) + * @see Kernel#put(char[] arr) + * @see Kernel#put(boolean[] arr) + */ + + public void put(Object array) { + if (explicit && (kernel.isRunningCL())) { + // Only makes sense when we are using OpenCL + puts.add(array); + } + } + + private boolean explicit = false; + + public void setExplicit(boolean _explicit) { + explicit = _explicit; + } + + public boolean isExplicit() { + return (explicit); + } + + private static class ExecutionSettings { + final KernelPreferences preferences; + final KernelProfile profile; + final String entrypoint; + Range range; + final int passes; + final boolean legacyExecutionMode; + + private ExecutionSettings(KernelPreferences preferences, KernelProfile profile, String entrypoint, Range range, int passes, boolean legacyExecutionMode) { + this.preferences = preferences; + this.profile = profile; + this.entrypoint = entrypoint; + this.range = range; + this.passes = passes; + this.legacyExecutionMode = legacyExecutionMode; + } + + @Override + public String toString() { + return "ExecutionSettings{" + + "preferences=" + preferences + + ", profile=" + profile + + ", entrypoint='" + entrypoint + '\'' + + ", range=" + range + + ", passes=" + passes + + ", legacyExecutionMode=" + legacyExecutionMode + + '}'; + } + } +} diff --git a/src/main/java/com/aparapi/internal/kernel/ProfilingEvent.java b/src/main/java/com/aparapi/internal/kernel/ProfilingEvent.java index 7a166567e39320da61aba7cb1ef814d37c53b703..bf0d5b553ae7926d029c3a59fa137428e35c2951 100644 --- a/src/main/java/com/aparapi/internal/kernel/ProfilingEvent.java +++ b/src/main/java/com/aparapi/internal/kernel/ProfilingEvent.java @@ -1,23 +1,23 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.kernel; - -/** - * Created by Barney on 02/09/2015. - */ -public enum ProfilingEvent { - START, CLASS_MODEL_BUILT, INIT_JNI, OPENCL_GENERATED, OPENCL_COMPILED, PREPARE_EXECUTE, EXECUTED -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.kernel; + +/** + * Created by Barney on 02/09/2015. + */ +public enum ProfilingEvent { + START, CLASS_MODEL_BUILT, INIT_JNI, OPENCL_GENERATED, OPENCL_COMPILED, PREPARE_EXECUTE, EXECUTED +} diff --git a/src/main/java/com/aparapi/internal/model/CacheEnabler.java b/src/main/java/com/aparapi/internal/model/CacheEnabler.java index 2ef0808acd45051c24b2b160d0e6f62333602bf7..35b1c888ec0578088b0aec4246148100bb31ca87 100644 --- a/src/main/java/com/aparapi/internal/model/CacheEnabler.java +++ b/src/main/java/com/aparapi/internal/model/CacheEnabler.java @@ -1,35 +1,35 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.model; - -import com.aparapi.Kernel; - -public class CacheEnabler{ - private static volatile boolean cachesEnabled = true; - - public static void setCachesEnabled(boolean cachesEnabled) { - if (CacheEnabler.cachesEnabled != cachesEnabled) { - Kernel.invalidateCaches(); - ClassModel.invalidateCaches(); - } - - CacheEnabler.cachesEnabled = cachesEnabled; - } - - public static boolean areCachesEnabled() { - return cachesEnabled; - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.model; + +import com.aparapi.Kernel; + +public class CacheEnabler{ + private static volatile boolean cachesEnabled = true; + + public static void setCachesEnabled(boolean cachesEnabled) { + if (CacheEnabler.cachesEnabled != cachesEnabled) { + Kernel.invalidateCaches(); + ClassModel.invalidateCaches(); + } + + CacheEnabler.cachesEnabled = cachesEnabled; + } + + public static boolean areCachesEnabled() { + return cachesEnabled; + } +} diff --git a/src/main/java/com/aparapi/internal/model/ClassModel.java b/src/main/java/com/aparapi/internal/model/ClassModel.java index e0ce45d0386d52fa12a77b2d1a6e4ace622a0866..db20a86b86427da185f8b74b0a13ff3eae2d4ff7 100644 --- a/src/main/java/com/aparapi/internal/model/ClassModel.java +++ b/src/main/java/com/aparapi/internal/model/ClassModel.java @@ -1,2864 +1,2864 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.model; - -import com.aparapi.*; -import com.aparapi.internal.annotation.*; -import com.aparapi.internal.exception.*; -import com.aparapi.internal.instruction.InstructionSet.*; -import com.aparapi.internal.model.ValueCache.ThrowingValueComputer; -import com.aparapi.internal.model.ClassModel.AttributePool.*; -import com.aparapi.internal.model.ClassModel.ConstantPool.*; -import com.aparapi.internal.reader.*; -import com.aparapi.internal.util.*; - -import java.io.*; -import java.lang.reflect.*; -import java.util.*; -import java.util.logging.*; - -/** - * Class represents a ClassFile (MyClass.class). - * - * A ClassModel is constructed from an instance of a <code>java.lang.Class</code>. - * - * If the java class mode changes we may need to modify this to accommodate. - * - * @see <a href="http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf">Java 5 Class File Format</a> -+ * @see <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html"> Java 7 Class File Format</a> - * - * @author gfrost - * - */ -public class ClassModel { - - public interface LocalVariableInfo { - - int getStart(); - - boolean isArray(); - - int getEnd(); - - String getVariableName(); - - String getVariableDescriptor(); - - int getVariableIndex(); - - int getLength(); - - } - - public interface LocalVariableTableEntry<T extends LocalVariableInfo> extends Iterable<T>{ - LocalVariableInfo getVariable(int _pc, int _index); - - } - - public static final char SIGC_VOID = 'V'; - - public static final char SIGC_BOOLEAN = 'Z'; - - public static final char SIGC_BYTE = 'B'; - - public static final char SIGC_CHAR = 'C'; - - public static final char SIGC_SHORT = 'S'; - - public static final char SIGC_INT = 'I'; - - public static final char SIGC_LONG = 'J'; - - public static final char SIGC_FLOAT = 'F'; - - public static final char SIGC_DOUBLE = 'D'; - - public static final char SIGC_ARRAY = '['; - - public static final char SIGC_CLASS = 'L'; - - public static final char SIGC_START_METHOD = '('; - - public static final char SIGC_END_CLASS = ';'; - - public static final char SIGC_END_METHOD = ')'; - - public static final char SIGC_PACKAGE = '/'; - - private static Logger logger = Logger.getLogger(Config.getLoggerName()); - - private ClassModel superClazz = null; - - // private Memoizer<Set<String>> noClMethods = Memoizer.of(this::computeNoCLMethods); - private Memoizer<Set<String>> noClMethods = Memoizer.Impl.of(new Supplier<Set<String>>(){ - @Override - public Set<String> get() { - return computeNoCLMethods(); - } - }); - - // private Memoizer<Map<String, Kernel.PrivateMemorySpace>> privateMemoryFields = Memoizer.of(this::computePrivateMemoryFields); - private Memoizer<Map<String, Kernel.PrivateMemorySpace>> privateMemoryFields = Memoizer.Impl - .of(new Supplier<Map<String, Kernel.PrivateMemorySpace>>(){ - @Override - public Map<String, Kernel.PrivateMemorySpace> get() { - return computePrivateMemoryFields(); - } - }); - - // private ValueCache<String, Integer, ClassParseException> privateMemorySizes = ValueCache.on(this::computePrivateMemorySize); - - private ValueCache<String, Integer, ClassParseException> privateMemorySizes = ValueCache - .on(new ThrowingValueComputer<String, Integer, ClassParseException>(){ - @Override - public Integer compute(String fieldName) throws ClassParseException { - return computePrivateMemorySize(fieldName); - } - }); - - /** - * Create a ClassModel representing a given Class. - * - * The class's classfile must be available from the class's classloader via <code>getClassLoader().getResourceAsStream(name))</code>. - * For dynamic languages creating classes on the fly we may need another approach. - * - * @param _class The class we will extract the model from - * @throws ClassParseException - */ - - private ClassModel(Class<?> _class) throws ClassParseException { - - parse(_class); - - final Class<?> mySuper = _class.getSuperclass(); - // Find better way to do this check - // The java.lang.Object test is for unit test framework to succeed - should - // not occur in normal use - if ((mySuper != null) && (!mySuper.getName().equals(Kernel.class.getName())) - && (!mySuper.getName().equals("java.lang.Object"))) { - superClazz = createClassModel(mySuper); - } - } - - ClassModel(InputStream _inputStream) throws ClassParseException { - - parse(_inputStream); - - } - - ClassModel(Class<?> _clazz, byte[] _bytes) throws ClassParseException { - clazz = _clazz; - parse(new ByteArrayInputStream(_bytes)); - } - - /** - * Determine if this is the superclass of some other named class. - * - * @param otherClassName The name of the class to compare against - * @return true if 'this' a superclass of another named class - */ - public boolean isSuperClass(String otherClassName) { - if (getClassWeAreModelling().getName().equals(otherClassName)) { - return true; - } else if (superClazz != null) { - return superClazz.isSuperClass(otherClassName); - } else { - return false; - } - } - - /** - * Determine if this is the superclass of some other class. - * - * @param other The class to compare against - * @return true if 'this' a superclass of another class - */ - public boolean isSuperClass(Class<?> other) { - Class<?> s = other.getSuperclass(); - while (s != null) { - if ((getClassWeAreModelling() == s) || (getClassWeAreModelling().getName().equals(s.getName()))) { - return true; - } - s = s.getSuperclass(); - } - return false; - } - - /** - * Getter for superClazz - * - * @return the superClazz ClassModel - */ - public ClassModel getSuperClazz() { - return superClazz; - } - - @DocMe - public void replaceSuperClazz(ClassModel c) { - if (superClazz != null) { - assert c.isSuperClass(getClassWeAreModelling()) == true : "not my super"; - if (superClazz.getClassWeAreModelling().getName().equals(c.getClassWeAreModelling().getName())) { - superClazz = c; - } else { - superClazz.replaceSuperClazz(c); - } - } - } - - /** - * Convert a given JNI character type (say 'I') to its type name ('int'). - * - * @param _typeChar - * @return either a mapped type name or null if no mapping exists. - */ - public static String typeName(char _typeChar) { - String returnName = null; - switch (_typeChar) { - case SIGC_VOID: - returnName = "void"; - break; - case SIGC_INT: - returnName = "int"; - break; - case SIGC_DOUBLE: - returnName = "double"; - break; - case SIGC_FLOAT: - returnName = "float"; - break; - case SIGC_SHORT: - returnName = "short"; - break; - case SIGC_CHAR: - returnName = "char"; - break; - case SIGC_BYTE: - returnName = "byte"; - break; - case SIGC_LONG: - returnName = "long"; - break; - case SIGC_BOOLEAN: - returnName = "boolean"; - break; - } - - return (returnName); - } - - /** - * If a field does not satisfy the private memory conditions, null, otherwise the size of private memory required. - */ - public Integer getPrivateMemorySize(String fieldName) throws ClassParseException { - if (CacheEnabler.areCachesEnabled()) - return privateMemorySizes.computeIfAbsent(fieldName); - return computePrivateMemorySize(fieldName); - } - - private Integer computePrivateMemorySize(String fieldName) throws ClassParseException { - Kernel.PrivateMemorySpace annotation = privateMemoryFields.get().get(fieldName); - if (annotation != null) { - return annotation.value(); - } - return getPrivateMemorySizeFromFieldName(fieldName); - } - - private Map<String, Kernel.PrivateMemorySpace> computePrivateMemoryFields() { - Map<String, Kernel.PrivateMemorySpace> tempPrivateMemoryFields = new HashMap<String, Kernel.PrivateMemorySpace>(); - Map<Field, Kernel.PrivateMemorySpace> privateMemoryFields = new HashMap<Field, Kernel.PrivateMemorySpace>(); - for (Field field : getClassWeAreModelling().getDeclaredFields()) { - Kernel.PrivateMemorySpace privateMemorySpace = field.getAnnotation(Kernel.PrivateMemorySpace.class); - if (privateMemorySpace != null) { - privateMemoryFields.put(field, privateMemorySpace); - } - } - for (Field field : getClassWeAreModelling().getFields()) { - Kernel.PrivateMemorySpace privateMemorySpace = field.getAnnotation(Kernel.PrivateMemorySpace.class); - if (privateMemorySpace != null) { - privateMemoryFields.put(field, privateMemorySpace); - } - } - for (Map.Entry<Field, Kernel.PrivateMemorySpace> entry : privateMemoryFields.entrySet()) { - tempPrivateMemoryFields.put(entry.getKey().getName(), entry.getValue()); - } - return tempPrivateMemoryFields; - } - - public static Integer getPrivateMemorySizeFromField(Field field) { - Kernel.PrivateMemorySpace privateMemorySpace = field.getAnnotation(Kernel.PrivateMemorySpace.class); - if (privateMemorySpace != null) { - return privateMemorySpace.value(); - } else { - return null; - } - } - - public static Integer getPrivateMemorySizeFromFieldName(String fieldName) throws ClassParseException { - if (fieldName.contains(Kernel.PRIVATE_SUFFIX)) { - int lastDollar = fieldName.lastIndexOf('$'); - String sizeText = fieldName.substring(lastDollar + 1); - try { - return new Integer(Integer.parseInt(sizeText)); - } catch (NumberFormatException e) { - throw new ClassParseException(ClassParseException.TYPE.IMPROPERPRIVATENAMEMANGLING, fieldName); - } - } - return null; - } - - public Set<String> getNoCLMethods() { - return computeNoCLMethods(); - } - - private Set<String> computeNoCLMethods() { - Set<String> tempNoClMethods = new HashSet<String>(); - HashSet<Method> methods = new HashSet<Method>(); - for (Method method : getClassWeAreModelling().getDeclaredMethods()) { - if (method.getAnnotation(Kernel.NoCL.class) != null) { - methods.add(method); - } - } - for (Method method : getClassWeAreModelling().getMethods()) { - if (method.getAnnotation(Kernel.NoCL.class) != null) { - methods.add(method); - } - } - for (Method method : methods) { - tempNoClMethods.add(method.getName()); - } - return tempNoClMethods; - } - - public static String convert(String _string) { - return (convert(_string, "", false)); - } - - public static String convert(String _string, String _insert) { - return (convert(_string, _insert, false)); - } - - public static String convert(String _string, String _insert, boolean _showFullClassName) { - Stack<String> stringStack = new Stack<String>(); - Stack<String> methodStack = null; - final int length = _string.length(); - final char[] chars = _string.toCharArray(); - int i = 0; - boolean inArray = false; - boolean inMethod = false; - boolean inArgs = false; - int args = 0; - - while (i < length) { - switch (chars[i]) { - case SIGC_CLASS: { - final StringBuilder classNameBuffer = new StringBuilder(); - i++; - while ((i < length) && (chars[i] != SIGC_END_CLASS)) { - if (chars[i] == SIGC_PACKAGE) { - classNameBuffer.append('.'); - } else { - classNameBuffer.append(chars[i]); - } - i++; - } - i++; // step over SIGC_ENDCLASS - String className = classNameBuffer.toString(); - if (_showFullClassName) { - if (className.startsWith("java.lang")) { - className = className.substring("java.lang.".length()); - } - } else { - final int lastDot = className.lastIndexOf('.'); - if (lastDot > 0) { - className = className.substring(lastDot + 1); - } - } - if (inArray) { - // swap the stack items - final String popped = stringStack.pop(); - if (inArgs && (args > 0)) { - stringStack.push(", "); - } - stringStack.push(className); - stringStack.push(popped); - inArray = false; - } else { - if (inArgs && (args > 0)) { - stringStack.push(", "); - } - stringStack.push(className); - } - args++; - } - break; - case SIGC_ARRAY: { - final StringBuilder arrayDims = new StringBuilder(); - while ((i < length) && (chars[i] == SIGC_ARRAY)) { - arrayDims.append("[]"); - i++; - } - stringStack.push(arrayDims.toString()); - inArray = true; - } - break; - case SIGC_VOID: - case SIGC_INT: - case SIGC_DOUBLE: - case SIGC_FLOAT: - case SIGC_SHORT: - case SIGC_CHAR: - case SIGC_BYTE: - case SIGC_LONG: - case SIGC_BOOLEAN: { - if (inArray) { - // swap the stack items - final String popped = stringStack.pop(); - if (inArgs && (args > 0)) { - stringStack.push(", "); - } - stringStack.push(typeName(chars[i])); - stringStack.push(popped); - inArray = false; - } else { - if (inArgs && (args > 0)) { - stringStack.push(", "); - } - stringStack.push(typeName(chars[i])); - } - i++; // step over this - } - break; - case SIGC_START_METHOD: { - stringStack.push("("); - i++; // step over this - inArgs = true; - args = 0; - } - break; - case SIGC_END_METHOD: { - inMethod = true; - inArgs = false; - stringStack.push(")"); - methodStack = stringStack; - stringStack = new Stack<String>(); - i++; // step over this - } - break; - } - } - - final StringBuilder returnValue = new StringBuilder(); - for (final String s : stringStack) { - returnValue.append(s); - returnValue.append(" "); - - } - - if (inMethod) { - for (final String s : methodStack) { - returnValue.append(s); - returnValue.append(" "); - } - } else { - returnValue.append(_insert); - } - - return (returnValue.toString()); - } - - public static class MethodDescription{ - private final String className; - - private final String methodName; - - private final String type; - - private final String[] args; - - public MethodDescription(String _className, String _methodName, String _type, String[] _args) { - methodName = _methodName; - className = _className; - type = _type; - args = _args; - } - - public String[] getArgs() { - return (args); - } - - public String getType() { - return (type); - } - - public String getClassName() { - return (className); - } - - public String getMethodName() { - return (methodName); - } - } - - public static MethodDescription getMethodDescription(String _string) { - String className = null; - String methodName = null; - String descriptor = null; - MethodDescription methodDescription = null; - - if (_string.startsWith("(")) { - className = "?"; - methodName = "?"; - descriptor = _string; - } else { - final int parenIndex = _string.indexOf("("); - final int dotIndex = _string.indexOf("."); - descriptor = _string.substring(parenIndex); - className = _string.substring(0, dotIndex); - methodName = _string.substring(dotIndex + 1, parenIndex); - } - - Stack<String> stringStack = new Stack<String>(); - Stack<String> methodStack = null; - final int length = descriptor.length(); - final char[] chars = new char[descriptor.length()]; - descriptor.getChars(0, descriptor.length(), chars, 0); - int i = 0; - boolean inArray = false; - boolean inMethod = false; - - while (i < length) { - switch (chars[i]) { - case SIGC_CLASS: { - StringBuilder stringBuffer = null; - if (inArray) { - stringBuffer = new StringBuilder(stringStack.pop()); - } else { - stringBuffer = new StringBuilder(); - } - while ((i < length) && (chars[i] != SIGC_END_CLASS)) { - stringBuffer.append(chars[i]); - i++; - } - stringBuffer.append(chars[i]); - i++; // step over SIGC_ENDCLASS - stringStack.push(stringBuffer.toString()); - inArray = false; - } - break; - case SIGC_ARRAY: { - final StringBuilder stringBuffer = new StringBuilder(); - while ((i < length) && (chars[i] == SIGC_ARRAY)) { - stringBuffer.append(chars[i]); - i++; - } - stringStack.push(stringBuffer.toString()); - inArray = true; - } - break; - case SIGC_VOID: - case SIGC_INT: - case SIGC_DOUBLE: - case SIGC_FLOAT: - case SIGC_SHORT: - case SIGC_CHAR: - case SIGC_BYTE: - case SIGC_LONG: - case SIGC_BOOLEAN: { - StringBuilder stringBuffer = null; - if (inArray) { - stringBuffer = new StringBuilder(stringStack.pop()); - } else { - stringBuffer = new StringBuilder(); - } - stringBuffer.append(chars[i]); - i++; // step over this - stringStack.push(stringBuffer.toString()); - inArray = false; - } - break; - case SIGC_START_METHOD: { - i++; // step over this - } - break; - case SIGC_END_METHOD: { - inMethod = true; - inArray = false; - methodStack = stringStack; - stringStack = new Stack<String>(); - i++; // step over this - } - break; - } - } - - if (inMethod) { - methodDescription = new MethodDescription(className, methodName, stringStack.toArray(new String[0])[0], - methodStack.toArray(new String[0])); - } else { - System.out.println("can't convert to a description"); - } - - return (methodDescription); - } - - private static final ValueCache<Class<?>, ClassModel, ClassParseException> classModelCache = ValueCache - .on(new ThrowingValueComputer<Class<?>, ClassModel, ClassParseException>(){ - @Override - public ClassModel compute(Class<?> key) throws ClassParseException { - return createClassModelInternal(key); - } - }); - - private static ClassModel createClassModelInternal(Class<?> key) throws ClassParseException { - ClassModel classModel = new ClassModel(key); - return classModel; - } - - public static ClassModel createClassModel(Class<?> _class) throws ClassParseException { - if (CacheEnabler.areCachesEnabled()) { - return classModelCache.computeIfAbsent(_class); - } - - return createClassModelInternal(_class); - } - - private int magic; - - private int minorVersion; - - private int majorVersion; - - private ConstantPool constantPool; - - private int accessFlags; - - private int thisClassConstantPoolIndex; - - private int superClassConstantPoolIndex; - - private final List<ClassModelInterface> interfaces = new ArrayList<ClassModelInterface>(); - - private final List<ClassModelField> fields = new ArrayList<ClassModelField>(); - - private final List<ClassModelMethod> methods = new ArrayList<ClassModelMethod>(); - - private AttributePool attributePool; - - public enum ConstantPoolType { - EMPTY, //0 - UTF8, //1 - UNICODE, //2 - INTEGER, //3 - FLOAT, //4 - LONG, //5 - DOUBLE, //6 - CLASS, //7 - STRING, //8 - FIELD, //9 - METHOD, //10 - INTERFACEMETHOD, //11 - NAMEANDTYPE, //12 - UNUSED13, - UNUSED14, - METHODHANDLE, //15 - METHODTYPE, //16 - UNUSED17, - INVOKEDYNAMIC//18 - }; - - public enum Access { - PUBLIC(0x00000001), - PRIVATE(0x00000002), - PROTECTED(0x00000004), - STATIC(0x00000008), - FINAL(0x00000010), - ACC_SYNCHRONIZED(0x00000020), - ACC_VOLATILE(0x00000040), - BRIDGE(0x00000040), - TRANSIENT(0x00000080), - VARARGS(0x00000080), - NATIVE(0x00000100), - INTERFACE(0x00000200), - ABSTRACT(0x00000400), - SUPER(0x00000020), - STRICT(0x00000800), - ANNOTATION(0x00002000), - ACC_ENUM(0x00004000); - int bits; - - private Access(int _bits) { - bits = _bits; - } - - public boolean bitIsSet(int _accessFlags) { - return ((bits & _accessFlags) == bits); - } - - public String convert(int _accessFlags) { - final StringBuffer stringBuffer = new StringBuffer(); - for (final Access access : Access.values()) { - if (access.bitIsSet(_accessFlags)) { - stringBuffer.append(" " + access.name().toLowerCase()); - } - } - - return (stringBuffer.toString()); - } - } - - private static enum SignatureParseState { - skipping, - counting, - inclass, - inArray, - done; - }; - - public class ConstantPool implements Iterable<ConstantPool.Entry>{ - - private final List<Entry> entries = new ArrayList<Entry>(); - - public abstract class Entry { - private final ConstantPoolType constantPoolType; - - private final int slot; - - public Entry(ByteReader _byteReader, int _slot, ConstantPoolType _constantPoolType) { - constantPoolType = _constantPoolType; - slot = _slot; - } - - public ConstantPoolType getConstantPoolType() { - return (constantPoolType); - } - - public int getSlot() { - return (slot); - } - - public ClassModel getOwnerClassModel() { - return ClassModel.this; - } - } - - public class ClassEntry extends Entry{ - private final int nameIndex; - - public ClassEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.CLASS); - nameIndex = _byteReader.u2(); - } - - public int getNameIndex() { - return (nameIndex); - } - - public UTF8Entry getNameUTF8Entry() { - return (getUTF8Entry(nameIndex)); - } - } - - public class DoubleEntry extends Entry{ - private final double doubleValue; - - public DoubleEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.DOUBLE); - doubleValue = _byteReader.d8(); - } - - public double getDoubleValue() { - return (doubleValue); - } - } - - public class EmptyEntry extends Entry{ - public EmptyEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.EMPTY); - } - } - - public class FieldEntry extends ReferenceEntry{ - public FieldEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.FIELD); - } - } - - public class FloatEntry extends Entry{ - private final float floatValue; - - public FloatEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.FLOAT); - floatValue = _byteReader.f4(); - } - - public float getFloatValue() { - return (floatValue); - } - } - - public class IntegerEntry extends Entry{ - private final int intValue; - - public IntegerEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.INTEGER); - intValue = _byteReader.u4(); - } - - public int getIntValue() { - return (intValue); - } - } - - public class InterfaceMethodEntry extends MethodReferenceEntry{ - InterfaceMethodEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.INTERFACEMETHOD); - } - } - - public class LongEntry extends Entry{ - private final long longValue; - - public LongEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.LONG); - longValue = _byteReader.u8(); - } - - public long getLongValue() { - return (longValue); - } - } - - public class MethodEntry extends MethodReferenceEntry{ - public MethodEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.METHOD); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append(getClassEntry().getNameUTF8Entry().getUTF8()); - sb.append("."); - sb.append(getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); - sb.append(getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8()); - return (sb.toString()); - } - } - - public class NameAndTypeEntry extends Entry{ - private final int descriptorIndex; - - private final int nameIndex; - - public NameAndTypeEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.NAMEANDTYPE); - nameIndex = _byteReader.u2(); - descriptorIndex = _byteReader.u2(); - } - - public int getDescriptorIndex() { - return (descriptorIndex); - } - - public UTF8Entry getDescriptorUTF8Entry() { - return (getUTF8Entry(descriptorIndex)); - } - - public int getNameIndex() { - return (nameIndex); - } - - public UTF8Entry getNameUTF8Entry() { - return (getUTF8Entry(nameIndex)); - } - } - - class MethodTypeEntry extends Entry{ - private int descriptorIndex; - - MethodTypeEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.METHODTYPE); - descriptorIndex = _byteReader.u2(); - } - - int getDescriptorIndex() { - return (descriptorIndex); - } - - UTF8Entry getDescriptorUTF8Entry() { - return (ConstantPool.this.getUTF8Entry(descriptorIndex)); - } - - } - - class MethodHandleEntry extends Entry{ - // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4 - - private int referenceKind; - - private int referenceIndex; - - MethodHandleEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.METHODHANDLE); - referenceKind = _byteReader.u1(); - referenceIndex = _byteReader.u2(); - } - - int getReferenceIndex() { - return (referenceIndex); - } - - int getReferenceKind() { - return (referenceKind); - } - - } - - class InvokeDynamicEntry extends Entry{ - // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4 - - private int bootstrapMethodAttrIndex; - - private int nameAndTypeIndex; - - InvokeDynamicEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.INVOKEDYNAMIC); - bootstrapMethodAttrIndex = _byteReader.u2(); - nameAndTypeIndex = _byteReader.u2(); - } - - int getBootstrapMethodAttrIndex() { - return (bootstrapMethodAttrIndex); - } - - int getNameAndTypeIndex() { - return (nameAndTypeIndex); - } - - } - - public abstract class MethodReferenceEntry extends ReferenceEntry{ - - public class Arg extends Type{ - Arg(String _signature, int _start, int _pos, int _argc) { - super(_signature.substring(_start, _pos + 1)); - argc = _argc; - } - - private final int argc; - - int getArgc() { - return (argc); - } - } - - private Arg[] args = null; - - private Type returnType = null; - - @Override - public int hashCode() { - final NameAndTypeEntry nameAndTypeEntry = getNameAndTypeEntry(); - - return ((((nameAndTypeEntry.getNameIndex() * 31) + nameAndTypeEntry.getDescriptorIndex()) * 31) + getClassIndex()); - } - - @Override - public boolean equals(Object _other) { - if ((_other == null) || !(_other instanceof MethodReferenceEntry)) { - return (false); - } else { - final MethodReferenceEntry otherMethodReferenceEntry = (MethodReferenceEntry) _other; - return ((otherMethodReferenceEntry.getNameAndTypeEntry().getNameIndex() == getNameAndTypeEntry().getNameIndex()) - && (otherMethodReferenceEntry.getNameAndTypeEntry().getDescriptorIndex() == getNameAndTypeEntry() - .getDescriptorIndex()) && (otherMethodReferenceEntry.getClassIndex() == getClassIndex())); - } - } - - public MethodReferenceEntry(ByteReader byteReader, int slot, ConstantPoolType constantPoolType) { - super(byteReader, slot, constantPoolType); - - } - - public int getStackProduceCount() { - return (getReturnType().isVoid() ? 0 : 1); - } - - public Type getReturnType() { - if (returnType == null) { - getArgs(); - } - - return (returnType); - } - - public Arg[] getArgs() { - if ((args == null) || (returnType == null)) { - final List<Arg> argList = new ArrayList<Arg>(); - final NameAndTypeEntry nameAndTypeEntry = getNameAndTypeEntry(); - - final String signature = nameAndTypeEntry.getDescriptorUTF8Entry().getUTF8();// "([[IF)V" for a method that takes an int[][], float and returns void. - // Sadly we need to parse this, we need the # of arguments for the call - SignatureParseState state = SignatureParseState.skipping; - int start = 0; - - for (int pos = 0; state != SignatureParseState.done; pos++) { - final char ch = signature.charAt(pos); - switch (ch) { - case '(': - state = SignatureParseState.counting; - break; - case ')': - state = SignatureParseState.done; - returnType = new Type(signature.substring(pos + 1)); - break; - case '[': - switch (state) { - case counting: - state = SignatureParseState.inArray; - start = pos; - break; - - } - // we don't care about arrays - break; - case 'L': - // beginning of Ljava/lang/String; or something - - switch (state) { - case counting: - start = pos; - // fallthrough intended!! - case inArray: - state = SignatureParseState.inclass; - break; - } - break; - case ';': - // note we will only be in 'inclass' if we were previously counting, so this is safe - switch (state) { - case inclass: - argList.add(new Arg(signature, start, pos, argList.size())); - state = SignatureParseState.counting; - break; - } - break; - - default: - // we have IJBZDF so inc counter if we are still counting - switch (state) { - case counting: - start = pos; - // fallthrough intended!! - case inArray: - argList.add(new Arg(signature, start, pos, argList.size())); - break; - - } - break; - } - } - // System.out.println("method "+name+" has signature of "+signature+" which has "+count+" args"); - - args = argList.toArray(new Arg[0]); - } - - return (args); - } - - public int getStackConsumeCount() { - return (getArgs().length); - } - } - - public abstract class ReferenceEntry extends Entry{ - protected int referenceClassIndex; - - protected int nameAndTypeIndex; - - protected int argCount = -1; - - public ReferenceEntry(ByteReader _byteReader, int _slot, ConstantPoolType _constantPoolType) { - super(_byteReader, _slot, _constantPoolType); - referenceClassIndex = _byteReader.u2(); - nameAndTypeIndex = _byteReader.u2(); - } - - public ClassEntry getClassEntry() { - return (ConstantPool.this.getClassEntry(referenceClassIndex)); - } - - public int getClassIndex() { - return (referenceClassIndex); - } - - public NameAndTypeEntry getNameAndTypeEntry() { - return (ConstantPool.this.getNameAndTypeEntry(nameAndTypeIndex)); - } - - public int getNameAndTypeIndex() { - return (nameAndTypeIndex); - } - - public boolean same(Entry _entry) { - if (_entry instanceof ReferenceEntry) { - final ReferenceEntry entry = (ReferenceEntry) _entry; - return ((referenceClassIndex == entry.referenceClassIndex) && (nameAndTypeIndex == entry.nameAndTypeIndex)); - } - - return (false); - } - - public class Type{ - private int arrayDimensions = 0; - - public Type(String _type) { - type = _type; - - while (type.charAt(arrayDimensions) == '[') { - arrayDimensions++; - } - type = type.substring(arrayDimensions); - } - - public String getType() { - return (type); - } - - public boolean isVoid() { - return (type.equals("V")); - } - - private String type; - - public boolean isArray() { - return (arrayDimensions > 0); - } - - public int getArrayDimensions() { - return (arrayDimensions); - } - } - } - - public class StringEntry extends Entry{ - private final int utf8Index; - - public StringEntry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.STRING); - utf8Index = _byteReader.u2(); - } - - public int getUTF8Index() { - return (utf8Index); - } - - public UTF8Entry getStringUTF8Entry() { - return (getUTF8Entry(utf8Index)); - } - } - - public class UTF8Entry extends Entry{ - private final String UTF8; - - public UTF8Entry(ByteReader _byteReader, int _slot) { - super(_byteReader, _slot, ConstantPoolType.UTF8); - UTF8 = _byteReader.utf8(); - } - - public String getUTF8() { - return (UTF8); - } - } - - public ConstantPool(ByteReader _byteReader) { - final int size = _byteReader.u2(); - add(new EmptyEntry(_byteReader, 0)); // slot 0 - - for (int i = 1; i < size; i++) { - final ConstantPoolType constantPoolType = ConstantPoolType.values()[_byteReader.u1()]; - - switch (constantPoolType) { - case UTF8: - add(new UTF8Entry(_byteReader, i)); - break; - case INTEGER: - add(new IntegerEntry(_byteReader, i)); - break; - case FLOAT: - add(new FloatEntry(_byteReader, i)); - break; - case LONG: - add(new LongEntry(_byteReader, i)); - i++;// Longs take two slots in the ConstantPool - add(new EmptyEntry(_byteReader, i)); - break; - case DOUBLE: - add(new DoubleEntry(_byteReader, i)); - i++; // Doubles take two slots in the ConstantPool - add(new EmptyEntry(_byteReader, i)); - break; - case CLASS: - add(new ClassEntry(_byteReader, i)); - break; - case STRING: - add(new StringEntry(_byteReader, i)); - break; - case FIELD: - add(new FieldEntry(_byteReader, i)); - break; - case METHOD: - add(new MethodEntry(_byteReader, i)); - break; - case INTERFACEMETHOD: - add(new InterfaceMethodEntry(_byteReader, i)); - break; - case NAMEANDTYPE: - add(new NameAndTypeEntry(_byteReader, i)); - break; - case METHODHANDLE: - add(new MethodHandleEntry(_byteReader, i)); - break; - case METHODTYPE: - add(new MethodTypeEntry(_byteReader, i)); - break; - case INVOKEDYNAMIC: - add(new InvokeDynamicEntry(_byteReader, i)); - break; - default: - System.out.printf("slot %04x unexpected Constant constantPoolType = %s\n", i, constantPoolType); - } - } - } - - public ClassEntry getClassEntry(int _index) { - try { - return ((ClassEntry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - public DoubleEntry getDoubleEntry(int _index) { - try { - return ((DoubleEntry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - public FieldEntry getFieldEntry(int _index) { - try { - return ((FieldEntry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - FieldEntry getFieldEntry(String _name) { - for (Entry entry : entries) { - if (entry instanceof FieldEntry) { - String fieldName = ((FieldEntry) entry).getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - if (_name.equals(fieldName)) { - return (FieldEntry) entry; - } - } - } - return null; - } - - public FloatEntry getFloatEntry(int _index) { - try { - return ((FloatEntry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - public IntegerEntry getIntegerEntry(int _index) { - try { - return ((IntegerEntry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - public InterfaceMethodEntry getInterfaceMethodEntry(int _index) { - try { - return ((InterfaceMethodEntry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - public LongEntry getLongEntry(int _index) { - try { - return ((LongEntry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - public MethodEntry getMethodEntry(int _index) { - try { - return ((MethodEntry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - public NameAndTypeEntry getNameAndTypeEntry(int _index) { - try { - return ((NameAndTypeEntry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - public StringEntry getStringEntry(int _index) { - try { - return ((StringEntry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - public UTF8Entry getUTF8Entry(int _index) { - try { - return ((UTF8Entry) entries.get(_index)); - } catch (final ClassCastException e) { - return (null); - } - } - - public void add(Entry _entry) { - entries.add(_entry); - - } - - @Override - public Iterator<Entry> iterator() { - return (entries.iterator()); - } - - public Entry get(int _index) { - return (entries.get(_index)); - } - - public String getDescription(ConstantPool.Entry _entry) { - final StringBuilder sb = new StringBuilder(); - if (_entry instanceof ConstantPool.EmptyEntry) { - ; - } else if (_entry instanceof ConstantPool.DoubleEntry) { - final ConstantPool.DoubleEntry doubleEntry = (ConstantPool.DoubleEntry) _entry; - sb.append(doubleEntry.getDoubleValue()); - } else if (_entry instanceof ConstantPool.FloatEntry) { - final ConstantPool.FloatEntry floatEntry = (ConstantPool.FloatEntry) _entry; - sb.append(floatEntry.getFloatValue()); - } else if (_entry instanceof ConstantPool.IntegerEntry) { - final ConstantPool.IntegerEntry integerEntry = (ConstantPool.IntegerEntry) _entry; - sb.append(integerEntry.getIntValue()); - } else if (_entry instanceof ConstantPool.LongEntry) { - final ConstantPool.LongEntry longEntry = (ConstantPool.LongEntry) _entry; - sb.append(longEntry.getLongValue()); - } else if (_entry instanceof ConstantPool.UTF8Entry) { - final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) _entry; - sb.append(utf8Entry.getUTF8()); - } else if (_entry instanceof ConstantPool.StringEntry) { - final ConstantPool.StringEntry stringEntry = (ConstantPool.StringEntry) _entry; - final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(stringEntry.getUTF8Index()); - sb.append(utf8Entry.getUTF8()); - } else if (_entry instanceof ConstantPool.ClassEntry) { - final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) _entry; - final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); - sb.append(utf8Entry.getUTF8()); - } else if (_entry instanceof ConstantPool.NameAndTypeEntry) { - final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) _entry; - final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); - final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); - sb.append(utf8NameEntry.getUTF8() + "." + utf8DescriptorEntry.getUTF8()); - } else if (_entry instanceof ConstantPool.MethodEntry) { - final ConstantPool.MethodEntry methodEntry = (ConstantPool.MethodEntry) _entry; - final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(methodEntry.getClassIndex()); - final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); - final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(methodEntry - .getNameAndTypeIndex()); - final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); - final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); - sb.append(convert(utf8DescriptorEntry.getUTF8(), utf8Entry.getUTF8() + "." + utf8NameEntry.getUTF8())); - } else if (_entry instanceof ConstantPool.InterfaceMethodEntry) { - final ConstantPool.InterfaceMethodEntry interfaceMethodEntry = (ConstantPool.InterfaceMethodEntry) _entry; - final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(interfaceMethodEntry.getClassIndex()); - final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); - final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(interfaceMethodEntry - .getNameAndTypeIndex()); - final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); - final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); - sb.append(convert(utf8DescriptorEntry.getUTF8(), utf8Entry.getUTF8() + "." + utf8NameEntry.getUTF8())); - } else if (_entry instanceof ConstantPool.FieldEntry) { - final ConstantPool.FieldEntry fieldEntry = (ConstantPool.FieldEntry) _entry; - final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(fieldEntry.getClassIndex()); - final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); - final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(fieldEntry - .getNameAndTypeIndex()); - final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); - final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); - sb.append(convert(utf8DescriptorEntry.getUTF8(), utf8Entry.getUTF8() + "." + utf8NameEntry.getUTF8())); - } - - return (sb.toString()); - } - - public int[] getConstantPoolReferences(ConstantPool.Entry _entry) { - int[] references = new int[0]; - if (_entry instanceof ConstantPool.StringEntry) { - final ConstantPool.StringEntry stringEntry = (ConstantPool.StringEntry) _entry; - references = new int[] { - stringEntry.getUTF8Index() - }; - } else if (_entry instanceof ConstantPool.ClassEntry) { - final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) _entry; - references = new int[] { - classEntry.getNameIndex() - }; - } else if (_entry instanceof ConstantPool.NameAndTypeEntry) { - final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) _entry; - references = new int[] { - nameAndTypeEntry.getNameIndex(), nameAndTypeEntry.getDescriptorIndex() - }; - } else if (_entry instanceof ConstantPool.MethodEntry) { - final ConstantPool.MethodEntry methodEntry = (ConstantPool.MethodEntry) _entry; - final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(methodEntry.getClassIndex()); - @SuppressWarnings("unused") - final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); - final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(methodEntry - .getNameAndTypeIndex()); - @SuppressWarnings("unused") - final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); - @SuppressWarnings("unused") - final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); - references = new int[] { - methodEntry.getClassIndex(), classEntry.getNameIndex(), nameAndTypeEntry.getNameIndex(), - nameAndTypeEntry.getDescriptorIndex() - }; - } else if (_entry instanceof ConstantPool.InterfaceMethodEntry) { - final ConstantPool.InterfaceMethodEntry interfaceMethodEntry = (ConstantPool.InterfaceMethodEntry) _entry; - final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(interfaceMethodEntry.getClassIndex()); - @SuppressWarnings("unused") - final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); - final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(interfaceMethodEntry - .getNameAndTypeIndex()); - @SuppressWarnings("unused") - final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); - @SuppressWarnings("unused") - final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); - references = new int[] { - interfaceMethodEntry.getClassIndex(), classEntry.getNameIndex(), nameAndTypeEntry.getNameIndex(), - nameAndTypeEntry.getDescriptorIndex() - }; - } else if (_entry instanceof ConstantPool.FieldEntry) { - final ConstantPool.FieldEntry fieldEntry = (ConstantPool.FieldEntry) _entry; - final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(fieldEntry.getClassIndex()); - @SuppressWarnings("unused") - final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); - final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(fieldEntry - .getNameAndTypeIndex()); - @SuppressWarnings("unused") - final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); - @SuppressWarnings("unused") - final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); - references = new int[] { - fieldEntry.getClassIndex(), classEntry.getNameIndex(), nameAndTypeEntry.getNameIndex(), - nameAndTypeEntry.getDescriptorIndex() - }; - } - - return (references); - } - - public String getType(ConstantPool.Entry _entry) { - final StringBuffer sb = new StringBuffer(); - if (_entry instanceof ConstantPool.EmptyEntry) { - sb.append("empty"); - } else if (_entry instanceof ConstantPool.DoubleEntry) { - sb.append("double"); - } else if (_entry instanceof ConstantPool.FloatEntry) { - sb.append("float"); - } else if (_entry instanceof ConstantPool.IntegerEntry) { - sb.append("int"); - } else if (_entry instanceof ConstantPool.LongEntry) { - sb.append("long"); - } else if (_entry instanceof ConstantPool.UTF8Entry) { - sb.append("utf8"); - } else if (_entry instanceof ConstantPool.StringEntry) { - sb.append("string"); - } else if (_entry instanceof ConstantPool.ClassEntry) { - sb.append("class"); - } else if (_entry instanceof ConstantPool.NameAndTypeEntry) { - sb.append("name/type"); - } else if (_entry instanceof ConstantPool.MethodEntry) { - sb.append("method"); - } else if (_entry instanceof ConstantPool.InterfaceMethodEntry) { - sb.append("interface method"); - } else if (_entry instanceof ConstantPool.FieldEntry) { - sb.append("field"); - } - - return (sb.toString()); - } - - public Object getConstantEntry(int _constantPoolIndex) { - final Entry entry = get(_constantPoolIndex); - Object object = null; - switch (entry.getConstantPoolType()) { - case FLOAT: - object = ((FloatEntry) entry).getFloatValue(); - break; - case DOUBLE: - object = ((DoubleEntry) entry).getDoubleValue(); - break; - case INTEGER: - object = ((IntegerEntry) entry).getIntValue(); - break; - case LONG: - object = ((LongEntry) entry).getLongValue(); - break; - case STRING: - object = ((StringEntry) entry).getStringUTF8Entry().getUTF8(); - break; - } - - return (object); - } - } - - public class AttributePool { - private final List<AttributePoolEntry> attributePoolEntries = new ArrayList<AttributePoolEntry>(); - - public class CodeEntry extends AttributePoolEntry{ - - public class ExceptionPoolEntry{ - private final int exceptionClassIndex; - - private final int end; - - private final int handler; - - private final int start; - - public ExceptionPoolEntry(ByteReader _byteReader) { - start = _byteReader.u2(); - end = _byteReader.u2(); - handler = _byteReader.u2(); - exceptionClassIndex = _byteReader.u2(); - } - - public ConstantPool.ClassEntry getClassEntry() { - return (constantPool.getClassEntry(exceptionClassIndex)); - } - - public int getClassIndex() { - return (exceptionClassIndex); - } - - public int getEnd() { - return (end); - } - - public int getHandler() { - return (handler); - } - - public int getStart() { - return (start); - } - } - - private final List<ExceptionPoolEntry> exceptionPoolEntries = new ArrayList<ExceptionPoolEntry>(); - - private final AttributePool codeEntryAttributePool; - - private final byte[] code; - - private final int maxLocals; - - private final int maxStack; - - public CodeEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - maxStack = _byteReader.u2(); - maxLocals = _byteReader.u2(); - final int codeLength = _byteReader.u4(); - code = _byteReader.bytes(codeLength); - final int exceptionTableLength = _byteReader.u2(); - - for (int i = 0; i < exceptionTableLength; i++) { - exceptionPoolEntries.add(new ExceptionPoolEntry(_byteReader)); - } - - codeEntryAttributePool = new AttributePool(_byteReader, getName()); - } - - @Override - public AttributePool getAttributePool() { - return (codeEntryAttributePool); - } - - public LineNumberTableEntry getLineNumberTableEntry() { - return (codeEntryAttributePool.getLineNumberTableEntry()); - } - - public int getMaxLocals() { - return (maxLocals); - } - - public int getMaxStack() { - return (maxStack); - } - - public byte[] getCode() { - return code; - } - - public List<ExceptionPoolEntry> getExceptionPoolEntries() { - return exceptionPoolEntries; - } - } - - public class ConstantValueEntry extends AttributePoolEntry{ - private final int index; - - public ConstantValueEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - index = _byteReader.u2(); - } - - public int getIndex() { - return (index); - } - - } - - public class DeprecatedEntry extends AttributePoolEntry{ - public DeprecatedEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - } - } - - public abstract class AttributePoolEntry { - protected int length; - - protected int nameIndex; - - public AttributePoolEntry(ByteReader _byteReader, int _nameIndex, int _length) { - nameIndex = _nameIndex; - length = _length; - } - - public AttributePool getAttributePool() { - return (null); - } - - public int getLength() { - return (length); - } - - public String getName() { - return (constantPool.getUTF8Entry(nameIndex).getUTF8()); - } - - public int getNameIndex() { - return (nameIndex); - } - } - - public abstract class PoolEntry<T> extends AttributePoolEntry implements Iterable<T>{ - private final List<T> pool = new ArrayList<T>(); - - public List<T> getPool() { - return (pool); - } - - public PoolEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - } - - @Override - public Iterator<T> iterator() { - return (pool.iterator()); - } - } - - public class ExceptionEntry extends PoolEntry<Integer>{ - public ExceptionEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - final int exceptionTableLength = _byteReader.u2(); - for (int i = 0; i < exceptionTableLength; i++) { - getPool().add(_byteReader.u2()); - } - } - } - - public class InnerClassesEntry extends PoolEntry<InnerClassesEntry.InnerClassInfo>{ - public class InnerClassInfo { - private final int innerAccess; - - private final int innerIndex; - - private final int innerNameIndex; - - private final int outerIndex; - - public InnerClassInfo(ByteReader _byteReader) { - innerIndex = _byteReader.u2(); - outerIndex = _byteReader.u2(); - innerNameIndex = _byteReader.u2(); - innerAccess = _byteReader.u2(); - } - - public int getInnerAccess() { - return (innerAccess); - } - - public int getInnerIndex() { - return (innerIndex); - } - - public int getInnerNameIndex() { - return (innerNameIndex); - } - - public int getOuterIndex() { - return (outerIndex); - } - } - - public InnerClassesEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - final int innerClassesTableLength = _byteReader.u2(); - for (int i = 0; i < innerClassesTableLength; i++) { - getPool().add(new InnerClassInfo(_byteReader)); - } - } - } - - public class LineNumberTableEntry extends PoolEntry<LineNumberTableEntry.StartLineNumberPair>{ - - public class StartLineNumberPair { - private final int lineNumber; - - private final int start; - - public StartLineNumberPair(ByteReader _byteReader) { - start = _byteReader.u2(); - lineNumber = _byteReader.u2(); - } - - public int getLineNumber() { - return (lineNumber); - } - - public int getStart() { - return (start); - } - } - - public LineNumberTableEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - final int lineNumberTableLength = _byteReader.u2(); - for (int i = 0; i < lineNumberTableLength; i++) { - getPool().add(new StartLineNumberPair(_byteReader)); - } - } - - public int getSourceLineNumber(int _start, boolean _exact) { - final Iterator<StartLineNumberPair> i = getPool().iterator(); - if (i.hasNext()) { - StartLineNumberPair from = i.next(); - while (i.hasNext()) { - final StartLineNumberPair to = i.next(); - if (_exact) { - if (_start == from.getStart()) { - return (from.getLineNumber()); - } - } else if ((_start >= from.getStart()) && (_start < to.getStart())) { - return (from.getLineNumber()); - } - from = to; - } - if (_exact) { - if (_start == from.getStart()) { - return (from.getLineNumber()); - } - } else if (_start >= from.getStart()) { - return (from.getLineNumber()); - } - } - - return (-1); - } - } - - public class EnclosingMethodEntry extends AttributePoolEntry{ - - public EnclosingMethodEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - enclosingClassIndex = _byteReader.u2(); - enclosingMethodIndex = _byteReader.u2(); - } - - private final int enclosingClassIndex; - - public int getClassIndex() { - return (enclosingClassIndex); - } - - private final int enclosingMethodIndex; - - public int getMethodIndex() { - return (enclosingMethodIndex); - } - } - - public class SignatureEntry extends AttributePoolEntry{ - - public SignatureEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - signatureIndex = _byteReader.u2(); - } - - private final int signatureIndex; - - int getSignatureIndex() { - return (signatureIndex); - } - } - - public class RealLocalVariableTableEntry extends PoolEntry<RealLocalVariableTableEntry.RealLocalVariableInfo> implements - LocalVariableTableEntry<RealLocalVariableTableEntry.RealLocalVariableInfo>{ - - class RealLocalVariableInfo implements LocalVariableInfo{ - private final int descriptorIndex; - - private final int usageLength; - - private final int variableNameIndex; - - private final int start; - - private final int variableIndex; - - public RealLocalVariableInfo(ByteReader _byteReader) { - start = _byteReader.u2(); - usageLength = _byteReader.u2(); - variableNameIndex = _byteReader.u2(); - descriptorIndex = _byteReader.u2(); - variableIndex = _byteReader.u2(); - } - - public int getDescriptorIndex() { - return (descriptorIndex); - } - - public int getLength() { - return (usageLength); - } - - public int getNameIndex() { - return (variableNameIndex); - } - - @Override - public int getStart() { - return (start); - } - - @Override - public int getVariableIndex() { - return (variableIndex); - } - - @Override - public String getVariableName() { - return (constantPool.getUTF8Entry(variableNameIndex).getUTF8()); - } - - @Override - public String getVariableDescriptor() { - return (constantPool.getUTF8Entry(descriptorIndex).getUTF8()); - } - - @Override - public int getEnd() { - return (start + usageLength); - } - - @Override - public boolean isArray() { - return (getVariableDescriptor().startsWith("[")); - } - } - - public RealLocalVariableTableEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - final int localVariableTableLength = _byteReader.u2(); - for (int i = 0; i < localVariableTableLength; i++) { - getPool().add(new RealLocalVariableInfo(_byteReader)); - } - } - - public RealLocalVariableInfo getVariable(int _pc, int _index) { - RealLocalVariableInfo returnValue = null; - // System.out.println("pc = " + _pc + " index = " + _index); - for (final RealLocalVariableInfo localVariableInfo : getPool()) { - // System.out.println(" start=" + localVariableInfo.getStart() + " length=" + localVariableInfo.getLength() - // + " varidx=" + localVariableInfo.getVariableIndex()); - if ((_pc >= (localVariableInfo.getStart() - 1)) - && (_pc <= (localVariableInfo.getStart() + localVariableInfo.getLength())) - && (_index == localVariableInfo.getVariableIndex())) { - returnValue = localVariableInfo; - break; - } - } - - // System.out.println("returning " + returnValue); - return (returnValue); - } - - public String getVariableName(int _pc, int _index) { - String returnValue = "unknown"; - final RealLocalVariableInfo localVariableInfo = (RealLocalVariableInfo) getVariable(_pc, _index); - if (localVariableInfo != null) { - returnValue = convert(constantPool.getUTF8Entry(localVariableInfo.getDescriptorIndex()).getUTF8(), constantPool - .getUTF8Entry(localVariableInfo.getNameIndex()).getUTF8()); - } - // System.out.println("returning " + returnValue); - return (returnValue); - } - } - - class BootstrapMethodsEntry extends AttributePoolEntry{ - // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.21 - class BootstrapMethod{ - class BootstrapArgument{ - public BootstrapArgument(ByteReader _byteReader) { - argument = _byteReader.u2(); - } - - int argument;// u2; - } - - public BootstrapMethod(ByteReader _byteReader) { - bootstrapMethodRef = _byteReader.u2(); - numBootstrapArguments = _byteReader.u2(); - bootstrapArguments = new BootstrapArgument[numBootstrapArguments]; - for (int i = 0; i < numBootstrapArguments; i++) { - bootstrapArguments[i] = new BootstrapArgument(_byteReader); - } - } - - int bootstrapMethodRef; //u2 - - int numBootstrapArguments; //u2 - - BootstrapArgument bootstrapArguments[]; - } - - BootstrapMethodsEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - numBootstrapMethods = _byteReader.u2(); - bootstrapMethods = new BootstrapMethod[numBootstrapMethods]; - for (int i = 0; i < numBootstrapMethods; i++) { - bootstrapMethods[i] = new BootstrapMethod(_byteReader); - } - } - - private int numBootstrapMethods; - - BootstrapMethod bootstrapMethods[]; - - int getNumBootstrapMethods() { - return (numBootstrapMethods); - } - - } - - public class OtherEntry extends AttributePoolEntry{ - private final byte[] bytes; - - public OtherEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - bytes = _byteReader.bytes(_length); - } - - public byte[] getBytes() { - return (bytes); - } - - @Override - public String toString() { - return (new String(bytes)); - } - - } - - class StackMapTableEntry extends AttributePoolEntry{ - private byte[] bytes; - - StackMapTableEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - bytes = _byteReader.bytes(_length); - } - - byte[] getBytes() { - return (bytes); - } - - @Override - public String toString() { - return (new String(bytes)); - } - } - - public class LocalVariableTypeTableEntry extends AttributePoolEntry{ - private byte[] bytes; - - public LocalVariableTypeTableEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - bytes = _byteReader.bytes(_length); - } - - public byte[] getBytes() { - return (bytes); - } - - @Override - public String toString() { - return (new String(bytes)); - } - } - - public class SourceFileEntry extends AttributePoolEntry{ - private final int sourceFileIndex; - - public SourceFileEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - sourceFileIndex = _byteReader.u2(); - } - - public int getSourceFileIndex() { - return (sourceFileIndex); - } - - public String getSourceFileName() { - return (constantPool.getUTF8Entry(sourceFileIndex).getUTF8()); - } - } - - public class SyntheticEntry extends AttributePoolEntry{ - public SyntheticEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - } - } - - public class RuntimeAnnotationsEntry extends PoolEntry<RuntimeAnnotationsEntry.AnnotationInfo>{ - - public class AnnotationInfo { - private final int typeIndex; - - private final int elementValuePairCount; - - public class ElementValuePair{ - class Value { - Value(int _tag) { - tag = _tag; - } - - int tag; - - } - - public class PrimitiveValue extends Value{ - private final int typeNameIndex; - - private final int constNameIndex; - - public PrimitiveValue(int _tag, ByteReader _byteReader) { - super(_tag); - typeNameIndex = _byteReader.u2(); - //constNameIndex = _byteReader.u2(); - constNameIndex = 0; - } - - public int getConstNameIndex() { - return (constNameIndex); - } - - public int getTypeNameIndex() { - return (typeNameIndex); - } - } - - public class EnumValue extends Value{ - EnumValue(int _tag, ByteReader _byteReader) { - super(_tag); - } - } - - public class ArrayValue extends Value{ - ArrayValue(int _tag, ByteReader _byteReader) { - super(_tag); - } - } - - public class ClassValue extends Value{ - ClassValue(int _tag, ByteReader _byteReader) { - super(_tag); - } - } - - public class AnnotationValue extends Value{ - AnnotationValue(int _tag, ByteReader _byteReader) { - super(_tag); - } - } - - @SuppressWarnings("unused") - private final int elementNameIndex; - - @SuppressWarnings("unused") - private Value value; - - public ElementValuePair(ByteReader _byteReader) { - elementNameIndex = _byteReader.u2(); - final int tag = _byteReader.u1(); - - switch (tag) { - case SIGC_BYTE: - case SIGC_CHAR: - case SIGC_INT: - case SIGC_LONG: - case SIGC_DOUBLE: - case SIGC_FLOAT: - case SIGC_SHORT: - case SIGC_BOOLEAN: - case 's': // special for String - value = new PrimitiveValue(tag, _byteReader); - break; - case 'e': // special for Enum - value = new EnumValue(tag, _byteReader); - break; - case 'c': // special for class - value = new ClassValue(tag, _byteReader); - break; - case '@': // special for Annotation - value = new AnnotationValue(tag, _byteReader); - break; - case 'a': // special for array - value = new ArrayValue(tag, _byteReader); - break; - } - } - } - - private final ElementValuePair[] elementValuePairs; - - public AnnotationInfo(ByteReader _byteReader) { - typeIndex = _byteReader.u2(); - elementValuePairCount = _byteReader.u2(); - elementValuePairs = new ElementValuePair[elementValuePairCount]; - for (int i = 0; i < elementValuePairCount; i++) { - elementValuePairs[i] = new ElementValuePair(_byteReader); - } - } - - public int getTypeIndex() { - return (typeIndex); - } - - public String getTypeDescriptor() { - return (constantPool.getUTF8Entry(typeIndex).getUTF8()); - } - } - - public RuntimeAnnotationsEntry(ByteReader _byteReader, int _nameIndex, int _length) { - super(_byteReader, _nameIndex, _length); - final int localVariableTableLength = _byteReader.u2(); - for (int i = 0; i < localVariableTableLength; i++) { - getPool().add(new AnnotationInfo(_byteReader)); - } - } - - } - - private CodeEntry codeEntry = null; - - private EnclosingMethodEntry enclosingMethodEntry = null; - - private DeprecatedEntry deprecatedEntry = null; - - private ExceptionEntry exceptionEntry = null; - - private LineNumberTableEntry lineNumberTableEntry = null; - - private LocalVariableTableEntry localVariableTableEntry = null; - - private RuntimeAnnotationsEntry runtimeVisibleAnnotationsEntry; - - private RuntimeAnnotationsEntry runtimeInvisibleAnnotationsEntry; - - private SourceFileEntry sourceFileEntry = null; - - private SyntheticEntry syntheticEntry = null; - - private BootstrapMethodsEntry bootstrapMethodsEntry = null; - - private final static String LOCALVARIABLETABLE_TAG = "LocalVariableTable"; - - private final static String CONSTANTVALUE_TAG = "ConstantValue"; - - private final static String LINENUMBERTABLE_TAG = "LineNumberTable"; - - private final static String SOURCEFILE_TAG = "SourceFile"; - - private final static String SYNTHETIC_TAG = "Synthetic"; - - private final static String EXCEPTIONS_TAG = "Exceptions"; - - private final static String INNERCLASSES_TAG = "InnerClasses"; - - private final static String DEPRECATED_TAG = "Deprecated"; - - private final static String CODE_TAG = "Code"; - - private final static String ENCLOSINGMETHOD_TAG = "EnclosingMethod"; - - private final static String SIGNATURE_TAG = "Signature"; - - private final static String RUNTIMEINVISIBLEANNOTATIONS_TAG = "RuntimeInvisibleAnnotations"; - - private final static String RUNTIMEVISIBLEANNOTATIONS_TAG = "RuntimeVisibleAnnotations"; - - private final static String BOOTSTRAPMETHODS_TAG = "BootstrapMethods"; - - private final static String STACKMAPTABLE_TAG = "StackMapTable"; - - private final static String LOCALVARIABLETYPETABLE_TAG = "LocalVariableTypeTable"; - - public AttributePool(ByteReader _byteReader, String name) { - final int attributeCount = _byteReader.u2(); - AttributePoolEntry entry = null; - for (int i = 0; i < attributeCount; i++) { - final int attributeNameIndex = _byteReader.u2(); - final int length = _byteReader.u4(); - UTF8Entry utf8Entry = constantPool.getUTF8Entry(attributeNameIndex); - if (utf8Entry == null) { - throw new IllegalStateException("corrupted state reading attributes for " + name); - } - final String attributeName = utf8Entry.getUTF8(); - if (attributeName.equals(LOCALVARIABLETABLE_TAG)) { - localVariableTableEntry = new RealLocalVariableTableEntry(_byteReader, attributeNameIndex, length); - entry = (RealLocalVariableTableEntry) localVariableTableEntry; - } else if (attributeName.equals(CONSTANTVALUE_TAG)) { - entry = new ConstantValueEntry(_byteReader, attributeNameIndex, length); - } else if (attributeName.equals(LINENUMBERTABLE_TAG)) { - lineNumberTableEntry = new LineNumberTableEntry(_byteReader, attributeNameIndex, length); - entry = lineNumberTableEntry; - } else if (attributeName.equals(SOURCEFILE_TAG)) { - sourceFileEntry = new SourceFileEntry(_byteReader, attributeNameIndex, length); - entry = sourceFileEntry; - } else if (attributeName.equals(SYNTHETIC_TAG)) { - syntheticEntry = new SyntheticEntry(_byteReader, attributeNameIndex, length); - entry = syntheticEntry; - } else if (attributeName.equals(EXCEPTIONS_TAG)) { - exceptionEntry = new ExceptionEntry(_byteReader, attributeNameIndex, length); - entry = exceptionEntry; - } else if (attributeName.equals(INNERCLASSES_TAG)) { - entry = new InnerClassesEntry(_byteReader, attributeNameIndex, length); - } else if (attributeName.equals(DEPRECATED_TAG)) { - deprecatedEntry = new DeprecatedEntry(_byteReader, attributeNameIndex, length); - entry = deprecatedEntry; - } else if (attributeName.equals(CODE_TAG)) { - codeEntry = new CodeEntry(_byteReader, attributeNameIndex, length); - entry = codeEntry; - } else if (attributeName.equals(ENCLOSINGMETHOD_TAG)) { - enclosingMethodEntry = new EnclosingMethodEntry(_byteReader, attributeNameIndex, length); - entry = enclosingMethodEntry; - } else if (attributeName.equals(SIGNATURE_TAG)) { - entry = new SignatureEntry(_byteReader, attributeNameIndex, length); - } else if (attributeName.equals(RUNTIMEINVISIBLEANNOTATIONS_TAG)) { - runtimeInvisibleAnnotationsEntry = new RuntimeAnnotationsEntry(_byteReader, attributeNameIndex, length); - entry = runtimeInvisibleAnnotationsEntry; - } else if (attributeName.equals(RUNTIMEVISIBLEANNOTATIONS_TAG)) { - runtimeVisibleAnnotationsEntry = new RuntimeAnnotationsEntry(_byteReader, attributeNameIndex, length); - entry = runtimeVisibleAnnotationsEntry; - } else if (attributeName.equals(BOOTSTRAPMETHODS_TAG)) { - bootstrapMethodsEntry = new BootstrapMethodsEntry(_byteReader, attributeNameIndex, length); - entry = bootstrapMethodsEntry; - // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.21 - } else if (attributeName.equals(STACKMAPTABLE_TAG)) { - // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.4 - - entry = new StackMapTableEntry(_byteReader, attributeNameIndex, length); - } else if (attributeName.equals(LOCALVARIABLETYPETABLE_TAG)) { - // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.14 - entry = new LocalVariableTypeTableEntry(_byteReader, attributeNameIndex, length); - } else { - logger.warning("Found unexpected Attribute (name = " + attributeName + ")"); - entry = new OtherEntry(_byteReader, attributeNameIndex, length); - } - attributePoolEntries.add(entry); - - } - } - - public CodeEntry getCodeEntry() { - return (codeEntry); - } - - public DeprecatedEntry getDeprecatedEntry() { - return (deprecatedEntry); - } - - public ExceptionEntry getExceptionEntry() { - return (exceptionEntry); - } - - public LineNumberTableEntry getLineNumberTableEntry() { - return (lineNumberTableEntry); - } - - public LocalVariableTableEntry getLocalVariableTableEntry() { - return (localVariableTableEntry); - } - - public SourceFileEntry getSourceFileEntry() { - return (sourceFileEntry); - } - - public SyntheticEntry getSyntheticEntry() { - return (syntheticEntry); - } - - public RuntimeAnnotationsEntry getRuntimeInvisibleAnnotationsEntry() { - return (runtimeInvisibleAnnotationsEntry); - } - - public RuntimeAnnotationsEntry getRuntimeVisibleAnnotationsEntry() { - return (runtimeVisibleAnnotationsEntry); - } - - public RuntimeAnnotationsEntry getBootstrap() { - return (runtimeVisibleAnnotationsEntry); - } - - } - - private static ClassLoader classModelLoader = ClassModel.class.getClassLoader(); - - public class ClassModelField { - private final int fieldAccessFlags; - - AttributePool fieldAttributePool; - - private final int descriptorIndex; - - private final int index; - - private final int nameIndex; - - public ClassModelField(ByteReader _byteReader, int _index) { - index = _index; - fieldAccessFlags = _byteReader.u2(); - nameIndex = _byteReader.u2(); - descriptorIndex = _byteReader.u2(); - fieldAttributePool = new AttributePool(_byteReader, getName()); - } - - public int getAccessFlags() { - return (fieldAccessFlags); - } - - public AttributePool getAttributePool() { - return (fieldAttributePool); - } - - public String getDescriptor() { - return (getDescriptorUTF8Entry().getUTF8()); - } - - public int getDescriptorIndex() { - return (descriptorIndex); - } - - public ConstantPool.UTF8Entry getDescriptorUTF8Entry() { - return (constantPool.getUTF8Entry(descriptorIndex)); - } - - public int getIndex() { - return (index); - } - - public String getName() { - return (getNameUTF8Entry().getUTF8()); - } - - public int getNameIndex() { - return (nameIndex); - } - - public ConstantPool.UTF8Entry getNameUTF8Entry() { - return (constantPool.getUTF8Entry(nameIndex)); - } - - public Class<?> getDeclaringClass() { - final String clazzName = getDescriptor().replaceAll("^L", "").replaceAll("/", ".").replaceAll(";$", ""); - try { - return (Class.forName(clazzName, true, classModelLoader)); - } catch (final ClassNotFoundException e) { - System.out.println("no class found for " + clazzName); - e.printStackTrace(); - return null; - } - } - } - - public class ClassModelMethod { - - private final int methodAccessFlags; - - private final AttributePool methodAttributePool; - - private final int descriptorIndex; - - private final int index; - - private final int nameIndex; - - private final CodeEntry codeEntry; - - public ClassModelMethod(ByteReader _byteReader, int _index) { - index = _index; - methodAccessFlags = _byteReader.u2(); - nameIndex = _byteReader.u2(); - descriptorIndex = _byteReader.u2(); - methodAttributePool = new AttributePool(_byteReader, getName()); - codeEntry = methodAttributePool.getCodeEntry(); - } - - public int getAccessFlags() { - return (methodAccessFlags); - } - - public boolean isStatic() { - return (Access.STATIC.bitIsSet(methodAccessFlags)); - } - - public AttributePool getAttributePool() { - return (methodAttributePool); - } - - public AttributePool.CodeEntry getCodeEntry() { - return (methodAttributePool.getCodeEntry()); - } - - public String getDescriptor() { - return (getDescriptorUTF8Entry().getUTF8()); - } - - public int getDescriptorIndex() { - return (descriptorIndex); - } - - public ConstantPool.UTF8Entry getDescriptorUTF8Entry() { - return (constantPool.getUTF8Entry(descriptorIndex)); - } - - public int getIndex() { - return (index); - } - - public String getName() { - return (getNameUTF8Entry().getUTF8()); - } - - public int getNameIndex() { - return (nameIndex); - } - - public ConstantPool.UTF8Entry getNameUTF8Entry() { - return (constantPool.getUTF8Entry(nameIndex)); - } - - public ConstantPool getConstantPool() { - return (constantPool); - } - - public AttributePool.LineNumberTableEntry getLineNumberTableEntry() { - return (getAttributePool().codeEntry.codeEntryAttributePool.lineNumberTableEntry); - } - - public LocalVariableTableEntry getLocalVariableTableEntry() { - return (getAttributePool().codeEntry.codeEntryAttributePool.localVariableTableEntry); - } - - void setLocalVariableTableEntry(LocalVariableTableEntry _localVariableTableEntry) { - getAttributePool().codeEntry.codeEntryAttributePool.localVariableTableEntry = _localVariableTableEntry; - } - - public LocalVariableInfo getLocalVariable(int _pc, int _index) { - return (getLocalVariableTableEntry().getVariable(_pc, _index)); - } - - public byte[] getCode() { - return (codeEntry.getCode()); - } - - public ClassModel getClassModel() { - return (ClassModel.this); - } - - public String toString() { - return getClassModel().getClassWeAreModelling().getName() + "." + getName() + " " + getDescriptor(); - } - - public ClassModel getOwnerClassModel() { - return ClassModel.this; - } - } - - public class ClassModelInterface { - private final int interfaceIndex; - - ClassModelInterface(ByteReader _byteReader) { - interfaceIndex = _byteReader.u2(); - } - - ConstantPool.ClassEntry getClassEntry() { - return (constantPool.getClassEntry(interfaceIndex)); - } - - int getInterfaceIndex() { - return (interfaceIndex); - } - - } - - private Class<?> clazz; - - /** - * We extract the class's classloader and name and delegate to private parse method. - * @param _class The class we wish to model - * @throws ClassParseException - */ - public void parse(Class<?> _class) throws ClassParseException { - - clazz = _class; - parse(_class.getClassLoader(), _class.getName()); - } - - /** - * Populate this model by parsing a given classfile from the given classloader. - * - * We create a ByteReader (wrapper around the bytes representing the classfile) and pass it to local inner classes to handle the various sections of the class file. - * - * @see ByteReader - * @see <a href="http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf">Java 5 Class File Format</a> - * @param _classLoader The classloader to access the classfile - * @param _className The name of the class to load (we convert '.' to '/' and append ".class" so you don't have to). - * @throws ClassParseException - */ - private void parse(ClassLoader _classLoader, String _className) throws ClassParseException { - - parse(_classLoader.getResourceAsStream(_className.replace('.', '/') + ".class")); - } - - void parse(InputStream _inputStream) throws ClassParseException { - - ByteReader byteReader = new ByteReader(_inputStream); - magic = byteReader.u4(); - minorVersion = byteReader.u2(); - majorVersion = byteReader.u2(); - constantPool = new ConstantPool(byteReader); - - accessFlags = byteReader.u2(); - thisClassConstantPoolIndex = byteReader.u2(); - superClassConstantPoolIndex = byteReader.u2(); - - final int interfaceCount = byteReader.u2(); - for (int i = 0; i < interfaceCount; i++) { - final ClassModelInterface iface = new ClassModelInterface(byteReader); - interfaces.add(iface); - } - - final int fieldCount = byteReader.u2(); - for (int i = 0; i < fieldCount; i++) { - final ClassModelField field = new ClassModelField(byteReader, i); - fields.add(field); - } - - final int methodPoolLength = byteReader.u2(); - for (int i = 0; i < methodPoolLength; i++) { - final ClassModelMethod method = new ClassModelMethod(byteReader, i); - methods.add(method); - } - - attributePool = new AttributePool(byteReader, Reflection.getSimpleName(getClassWeAreModelling())); - } - - public int getMagic() { - return (magic); - } - - public int getMajorVersion() { - return (majorVersion); - } - - public int getMinorVersion() { - return (minorVersion); - } - - public int getAccessFlags() { - return (accessFlags); - } - - public ConstantPool getConstantPool() { - return (constantPool); - } - - public int getThisClassConstantPoolIndex() { - return (thisClassConstantPoolIndex); - } - - public int getSuperClassConstantPoolIndex() { - return (superClassConstantPoolIndex); - } - - public AttributePool getAttributePool() { - return (attributePool); - } - - public ClassModelField getField(String _name, String _descriptor) { - for (final ClassModelField entry : fields) { - if (entry.getName().equals(_name) && entry.getDescriptor().equals(_descriptor)) { - return (entry); - } - } - return superClazz.getField(_name, _descriptor); - } - - public ClassModelField getField(String _name) { - for (final ClassModelField entry : fields) { - if (entry.getName().equals(_name)) { - return (entry); - } - } - return superClazz.getField(_name); - } - - public ClassModelMethod getMethod(String _name, String _descriptor) { - ClassModelMethod methodOrNull = getMethodOrNull(_name, _descriptor); - if (methodOrNull == null) - return superClazz != null ? superClazz.getMethod(_name, _descriptor) : (null); - return methodOrNull; - } - - private ClassModelMethod getMethodOrNull(String _name, String _descriptor) { - for (final ClassModelMethod entry : methods) { - if (entry.getName().equals(_name) && entry.getDescriptor().equals(_descriptor)) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Found " + clazz.getName() + "." + entry.getName() + " " + entry.getDescriptor() + " for " - + _name.replace('/', '.')); - } - return (entry); - } - } - return null; - } - - public List<ClassModelField> getFieldPoolEntries() { - return (fields); - } - - /** - * Look up a ConstantPool MethodEntry and return the corresponding Method. - * - * @param _methodEntry The ConstantPool MethodEntry we want. - * @param _isSpecial True if we wish to delegate to super (to support <code>super.foo()</code>) - * - * @return The Method or null if we fail to locate a given method. - */ - public ClassModelMethod getMethod(MethodEntry _methodEntry, boolean _isSpecial) { - final String entryClassNameInDotForm = _methodEntry.getClassEntry().getNameUTF8Entry().getUTF8().replace('/', '.'); - - // Shortcut direct calls to supers to allow "foo() { super.foo() }" type stuff to work - if (_isSpecial && (superClazz != null) && superClazz.isSuperClass(entryClassNameInDotForm)) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("going to look in super:" + superClazz.getClassWeAreModelling().getName() + " on behalf of " - + entryClassNameInDotForm); - } - return superClazz.getMethod(_methodEntry, false); - } - - NameAndTypeEntry nameAndTypeEntry = _methodEntry.getNameAndTypeEntry(); - ClassModelMethod methodOrNull = getMethodOrNull(nameAndTypeEntry.getNameUTF8Entry().getUTF8(), nameAndTypeEntry - .getDescriptorUTF8Entry().getUTF8()); - if (methodOrNull == null) - return superClazz != null ? superClazz.getMethod(_methodEntry, false) : (null); - return methodOrNull; - } - - // private ValueCache<MethodKey, MethodModel, AparapiException> methodModelCache = ValueCache.on(this::computeMethodModel); - private ValueCache<MethodKey, MethodModel, AparapiException> methodModelCache = ValueCache - .on(new ThrowingValueComputer<MethodKey, MethodModel, AparapiException>(){ - @Override public MethodModel compute(MethodKey key) throws AparapiException { - return computeMethodModel(key); - } - }); - - /** - * Create a MethodModel for a given method name and signature. - * - * @param _name - * @param _signature - * @return - * @throws AparapiException - */ - public MethodModel getMethodModel(String _name, String _signature) throws AparapiException { - if (CacheEnabler.areCachesEnabled()) - return methodModelCache.computeIfAbsent(MethodKey.of(_name, _signature)); - else { - final ClassModelMethod method = getMethod(_name, _signature); - return new MethodModel(method); - } - } - - private MethodModel computeMethodModel(MethodKey methodKey) throws AparapiException { - final ClassModelMethod method = getMethod(methodKey.getName(), methodKey.getSignature()); - return new MethodModel(method); - } - - // These fields use for accessor conversion - private final ArrayList<FieldEntry> structMembers = new ArrayList<FieldEntry>(); - - private final ArrayList<Long> structMemberOffsets = new ArrayList<Long>(); - - private final ArrayList<TypeSpec> structMemberTypes = new ArrayList<TypeSpec>(); - - private int totalStructSize = 0; - - public ArrayList<FieldEntry> getStructMembers() { - return structMembers; - } - - public ArrayList<Long> getStructMemberOffsets() { - return structMemberOffsets; - } - - public ArrayList<TypeSpec> getStructMemberTypes() { - return structMemberTypes; - } - - public int getTotalStructSize() { - return totalStructSize; - } - - public void setTotalStructSize(int x) { - totalStructSize = x; - } - - // private final ValueCache<EntrypointKey, Entrypoint, AparapiException> entrypointCache = ValueCache.on(this::computeBasicEntrypoint); - private final ValueCache<EntrypointKey, Entrypoint, AparapiException> entrypointCache = ValueCache - .on(new ThrowingValueComputer<EntrypointKey, Entrypoint, AparapiException>(){ - @Override public Entrypoint compute(EntrypointKey key) throws AparapiException { - return computeBasicEntrypoint(key); - } - }); - - Entrypoint getEntrypoint(String _entrypointName, String _descriptor, Object _k) throws AparapiException { - if (CacheEnabler.areCachesEnabled()) { - EntrypointKey key = EntrypointKey.of(_entrypointName, _descriptor); - long s = System.nanoTime(); - Entrypoint entrypointWithoutKernel = entrypointCache.computeIfAbsent(key); - long e = System.nanoTime() - s; - return entrypointWithoutKernel.cloneForKernel(_k); - } else { - final MethodModel method = getMethodModel(_entrypointName, _descriptor); - return new Entrypoint(this, method, _k); - } - } - - Entrypoint computeBasicEntrypoint(EntrypointKey entrypointKey) throws AparapiException { - final MethodModel method = getMethodModel(entrypointKey.getEntrypointName(), entrypointKey.getDescriptor()); - return new Entrypoint(this, method, null); - } - - public Class<?> getClassWeAreModelling() { - return clazz; - } - - public Entrypoint getEntrypoint(String _entrypointName, Object _k) throws AparapiException { - return (getEntrypoint(_entrypointName, "()V", _k)); - } - - public Entrypoint getEntrypoint() throws AparapiException { - return (getEntrypoint("run", "()V", null)); - } - - public static void invalidateCaches() { - classModelCache.invalidate(); - } - - @Override public String toString() { - return "ClassModel of " + getClassWeAreModelling(); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.model; + +import com.aparapi.*; +import com.aparapi.internal.annotation.*; +import com.aparapi.internal.exception.*; +import com.aparapi.internal.instruction.InstructionSet.*; +import com.aparapi.internal.model.ValueCache.ThrowingValueComputer; +import com.aparapi.internal.model.ClassModel.AttributePool.*; +import com.aparapi.internal.model.ClassModel.ConstantPool.*; +import com.aparapi.internal.reader.*; +import com.aparapi.internal.util.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.logging.*; + +/** + * Class represents a ClassFile (MyClass.class). + * + * A ClassModel is constructed from an instance of a <code>java.lang.Class</code>. + * + * If the java class mode changes we may need to modify this to accommodate. + * + * @see <a href="http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf">Java 5 Class File Format</a> ++ * @see <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html"> Java 7 Class File Format</a> + * + * @author gfrost + * + */ +public class ClassModel { + + public interface LocalVariableInfo { + + int getStart(); + + boolean isArray(); + + int getEnd(); + + String getVariableName(); + + String getVariableDescriptor(); + + int getVariableIndex(); + + int getLength(); + + } + + public interface LocalVariableTableEntry<T extends LocalVariableInfo> extends Iterable<T>{ + LocalVariableInfo getVariable(int _pc, int _index); + + } + + public static final char SIGC_VOID = 'V'; + + public static final char SIGC_BOOLEAN = 'Z'; + + public static final char SIGC_BYTE = 'B'; + + public static final char SIGC_CHAR = 'C'; + + public static final char SIGC_SHORT = 'S'; + + public static final char SIGC_INT = 'I'; + + public static final char SIGC_LONG = 'J'; + + public static final char SIGC_FLOAT = 'F'; + + public static final char SIGC_DOUBLE = 'D'; + + public static final char SIGC_ARRAY = '['; + + public static final char SIGC_CLASS = 'L'; + + public static final char SIGC_START_METHOD = '('; + + public static final char SIGC_END_CLASS = ';'; + + public static final char SIGC_END_METHOD = ')'; + + public static final char SIGC_PACKAGE = '/'; + + private static Logger logger = Logger.getLogger(Config.getLoggerName()); + + private ClassModel superClazz = null; + + // private Memoizer<Set<String>> noClMethods = Memoizer.of(this::computeNoCLMethods); + private Memoizer<Set<String>> noClMethods = Memoizer.Impl.of(new Supplier<Set<String>>(){ + @Override + public Set<String> get() { + return computeNoCLMethods(); + } + }); + + // private Memoizer<Map<String, Kernel.PrivateMemorySpace>> privateMemoryFields = Memoizer.of(this::computePrivateMemoryFields); + private Memoizer<Map<String, Kernel.PrivateMemorySpace>> privateMemoryFields = Memoizer.Impl + .of(new Supplier<Map<String, Kernel.PrivateMemorySpace>>(){ + @Override + public Map<String, Kernel.PrivateMemorySpace> get() { + return computePrivateMemoryFields(); + } + }); + + // private ValueCache<String, Integer, ClassParseException> privateMemorySizes = ValueCache.on(this::computePrivateMemorySize); + + private ValueCache<String, Integer, ClassParseException> privateMemorySizes = ValueCache + .on(new ThrowingValueComputer<String, Integer, ClassParseException>(){ + @Override + public Integer compute(String fieldName) throws ClassParseException { + return computePrivateMemorySize(fieldName); + } + }); + + /** + * Create a ClassModel representing a given Class. + * + * The class's classfile must be available from the class's classloader via <code>getClassLoader().getResourceAsStream(name))</code>. + * For dynamic languages creating classes on the fly we may need another approach. + * + * @param _class The class we will extract the model from + * @throws ClassParseException + */ + + private ClassModel(Class<?> _class) throws ClassParseException { + + parse(_class); + + final Class<?> mySuper = _class.getSuperclass(); + // Find better way to do this check + // The java.lang.Object test is for unit test framework to succeed - should + // not occur in normal use + if ((mySuper != null) && (!mySuper.getName().equals(Kernel.class.getName())) + && (!mySuper.getName().equals("java.lang.Object"))) { + superClazz = createClassModel(mySuper); + } + } + + ClassModel(InputStream _inputStream) throws ClassParseException { + + parse(_inputStream); + + } + + ClassModel(Class<?> _clazz, byte[] _bytes) throws ClassParseException { + clazz = _clazz; + parse(new ByteArrayInputStream(_bytes)); + } + + /** + * Determine if this is the superclass of some other named class. + * + * @param otherClassName The name of the class to compare against + * @return true if 'this' a superclass of another named class + */ + public boolean isSuperClass(String otherClassName) { + if (getClassWeAreModelling().getName().equals(otherClassName)) { + return true; + } else if (superClazz != null) { + return superClazz.isSuperClass(otherClassName); + } else { + return false; + } + } + + /** + * Determine if this is the superclass of some other class. + * + * @param other The class to compare against + * @return true if 'this' a superclass of another class + */ + public boolean isSuperClass(Class<?> other) { + Class<?> s = other.getSuperclass(); + while (s != null) { + if ((getClassWeAreModelling() == s) || (getClassWeAreModelling().getName().equals(s.getName()))) { + return true; + } + s = s.getSuperclass(); + } + return false; + } + + /** + * Getter for superClazz + * + * @return the superClazz ClassModel + */ + public ClassModel getSuperClazz() { + return superClazz; + } + + @DocMe + public void replaceSuperClazz(ClassModel c) { + if (superClazz != null) { + assert c.isSuperClass(getClassWeAreModelling()) == true : "not my super"; + if (superClazz.getClassWeAreModelling().getName().equals(c.getClassWeAreModelling().getName())) { + superClazz = c; + } else { + superClazz.replaceSuperClazz(c); + } + } + } + + /** + * Convert a given JNI character type (say 'I') to its type name ('int'). + * + * @param _typeChar + * @return either a mapped type name or null if no mapping exists. + */ + public static String typeName(char _typeChar) { + String returnName = null; + switch (_typeChar) { + case SIGC_VOID: + returnName = "void"; + break; + case SIGC_INT: + returnName = "int"; + break; + case SIGC_DOUBLE: + returnName = "double"; + break; + case SIGC_FLOAT: + returnName = "float"; + break; + case SIGC_SHORT: + returnName = "short"; + break; + case SIGC_CHAR: + returnName = "char"; + break; + case SIGC_BYTE: + returnName = "byte"; + break; + case SIGC_LONG: + returnName = "long"; + break; + case SIGC_BOOLEAN: + returnName = "boolean"; + break; + } + + return (returnName); + } + + /** + * If a field does not satisfy the private memory conditions, null, otherwise the size of private memory required. + */ + public Integer getPrivateMemorySize(String fieldName) throws ClassParseException { + if (CacheEnabler.areCachesEnabled()) + return privateMemorySizes.computeIfAbsent(fieldName); + return computePrivateMemorySize(fieldName); + } + + private Integer computePrivateMemorySize(String fieldName) throws ClassParseException { + Kernel.PrivateMemorySpace annotation = privateMemoryFields.get().get(fieldName); + if (annotation != null) { + return annotation.value(); + } + return getPrivateMemorySizeFromFieldName(fieldName); + } + + private Map<String, Kernel.PrivateMemorySpace> computePrivateMemoryFields() { + Map<String, Kernel.PrivateMemorySpace> tempPrivateMemoryFields = new HashMap<String, Kernel.PrivateMemorySpace>(); + Map<Field, Kernel.PrivateMemorySpace> privateMemoryFields = new HashMap<Field, Kernel.PrivateMemorySpace>(); + for (Field field : getClassWeAreModelling().getDeclaredFields()) { + Kernel.PrivateMemorySpace privateMemorySpace = field.getAnnotation(Kernel.PrivateMemorySpace.class); + if (privateMemorySpace != null) { + privateMemoryFields.put(field, privateMemorySpace); + } + } + for (Field field : getClassWeAreModelling().getFields()) { + Kernel.PrivateMemorySpace privateMemorySpace = field.getAnnotation(Kernel.PrivateMemorySpace.class); + if (privateMemorySpace != null) { + privateMemoryFields.put(field, privateMemorySpace); + } + } + for (Map.Entry<Field, Kernel.PrivateMemorySpace> entry : privateMemoryFields.entrySet()) { + tempPrivateMemoryFields.put(entry.getKey().getName(), entry.getValue()); + } + return tempPrivateMemoryFields; + } + + public static Integer getPrivateMemorySizeFromField(Field field) { + Kernel.PrivateMemorySpace privateMemorySpace = field.getAnnotation(Kernel.PrivateMemorySpace.class); + if (privateMemorySpace != null) { + return privateMemorySpace.value(); + } else { + return null; + } + } + + public static Integer getPrivateMemorySizeFromFieldName(String fieldName) throws ClassParseException { + if (fieldName.contains(Kernel.PRIVATE_SUFFIX)) { + int lastDollar = fieldName.lastIndexOf('$'); + String sizeText = fieldName.substring(lastDollar + 1); + try { + return new Integer(Integer.parseInt(sizeText)); + } catch (NumberFormatException e) { + throw new ClassParseException(ClassParseException.TYPE.IMPROPERPRIVATENAMEMANGLING, fieldName); + } + } + return null; + } + + public Set<String> getNoCLMethods() { + return computeNoCLMethods(); + } + + private Set<String> computeNoCLMethods() { + Set<String> tempNoClMethods = new HashSet<String>(); + HashSet<Method> methods = new HashSet<Method>(); + for (Method method : getClassWeAreModelling().getDeclaredMethods()) { + if (method.getAnnotation(Kernel.NoCL.class) != null) { + methods.add(method); + } + } + for (Method method : getClassWeAreModelling().getMethods()) { + if (method.getAnnotation(Kernel.NoCL.class) != null) { + methods.add(method); + } + } + for (Method method : methods) { + tempNoClMethods.add(method.getName()); + } + return tempNoClMethods; + } + + public static String convert(String _string) { + return (convert(_string, "", false)); + } + + public static String convert(String _string, String _insert) { + return (convert(_string, _insert, false)); + } + + public static String convert(String _string, String _insert, boolean _showFullClassName) { + Stack<String> stringStack = new Stack<String>(); + Stack<String> methodStack = null; + final int length = _string.length(); + final char[] chars = _string.toCharArray(); + int i = 0; + boolean inArray = false; + boolean inMethod = false; + boolean inArgs = false; + int args = 0; + + while (i < length) { + switch (chars[i]) { + case SIGC_CLASS: { + final StringBuilder classNameBuffer = new StringBuilder(); + i++; + while ((i < length) && (chars[i] != SIGC_END_CLASS)) { + if (chars[i] == SIGC_PACKAGE) { + classNameBuffer.append('.'); + } else { + classNameBuffer.append(chars[i]); + } + i++; + } + i++; // step over SIGC_ENDCLASS + String className = classNameBuffer.toString(); + if (_showFullClassName) { + if (className.startsWith("java.lang")) { + className = className.substring("java.lang.".length()); + } + } else { + final int lastDot = className.lastIndexOf('.'); + if (lastDot > 0) { + className = className.substring(lastDot + 1); + } + } + if (inArray) { + // swap the stack items + final String popped = stringStack.pop(); + if (inArgs && (args > 0)) { + stringStack.push(", "); + } + stringStack.push(className); + stringStack.push(popped); + inArray = false; + } else { + if (inArgs && (args > 0)) { + stringStack.push(", "); + } + stringStack.push(className); + } + args++; + } + break; + case SIGC_ARRAY: { + final StringBuilder arrayDims = new StringBuilder(); + while ((i < length) && (chars[i] == SIGC_ARRAY)) { + arrayDims.append("[]"); + i++; + } + stringStack.push(arrayDims.toString()); + inArray = true; + } + break; + case SIGC_VOID: + case SIGC_INT: + case SIGC_DOUBLE: + case SIGC_FLOAT: + case SIGC_SHORT: + case SIGC_CHAR: + case SIGC_BYTE: + case SIGC_LONG: + case SIGC_BOOLEAN: { + if (inArray) { + // swap the stack items + final String popped = stringStack.pop(); + if (inArgs && (args > 0)) { + stringStack.push(", "); + } + stringStack.push(typeName(chars[i])); + stringStack.push(popped); + inArray = false; + } else { + if (inArgs && (args > 0)) { + stringStack.push(", "); + } + stringStack.push(typeName(chars[i])); + } + i++; // step over this + } + break; + case SIGC_START_METHOD: { + stringStack.push("("); + i++; // step over this + inArgs = true; + args = 0; + } + break; + case SIGC_END_METHOD: { + inMethod = true; + inArgs = false; + stringStack.push(")"); + methodStack = stringStack; + stringStack = new Stack<String>(); + i++; // step over this + } + break; + } + } + + final StringBuilder returnValue = new StringBuilder(); + for (final String s : stringStack) { + returnValue.append(s); + returnValue.append(" "); + + } + + if (inMethod) { + for (final String s : methodStack) { + returnValue.append(s); + returnValue.append(" "); + } + } else { + returnValue.append(_insert); + } + + return (returnValue.toString()); + } + + public static class MethodDescription{ + private final String className; + + private final String methodName; + + private final String type; + + private final String[] args; + + public MethodDescription(String _className, String _methodName, String _type, String[] _args) { + methodName = _methodName; + className = _className; + type = _type; + args = _args; + } + + public String[] getArgs() { + return (args); + } + + public String getType() { + return (type); + } + + public String getClassName() { + return (className); + } + + public String getMethodName() { + return (methodName); + } + } + + public static MethodDescription getMethodDescription(String _string) { + String className = null; + String methodName = null; + String descriptor = null; + MethodDescription methodDescription = null; + + if (_string.startsWith("(")) { + className = "?"; + methodName = "?"; + descriptor = _string; + } else { + final int parenIndex = _string.indexOf("("); + final int dotIndex = _string.indexOf("."); + descriptor = _string.substring(parenIndex); + className = _string.substring(0, dotIndex); + methodName = _string.substring(dotIndex + 1, parenIndex); + } + + Stack<String> stringStack = new Stack<String>(); + Stack<String> methodStack = null; + final int length = descriptor.length(); + final char[] chars = new char[descriptor.length()]; + descriptor.getChars(0, descriptor.length(), chars, 0); + int i = 0; + boolean inArray = false; + boolean inMethod = false; + + while (i < length) { + switch (chars[i]) { + case SIGC_CLASS: { + StringBuilder stringBuffer = null; + if (inArray) { + stringBuffer = new StringBuilder(stringStack.pop()); + } else { + stringBuffer = new StringBuilder(); + } + while ((i < length) && (chars[i] != SIGC_END_CLASS)) { + stringBuffer.append(chars[i]); + i++; + } + stringBuffer.append(chars[i]); + i++; // step over SIGC_ENDCLASS + stringStack.push(stringBuffer.toString()); + inArray = false; + } + break; + case SIGC_ARRAY: { + final StringBuilder stringBuffer = new StringBuilder(); + while ((i < length) && (chars[i] == SIGC_ARRAY)) { + stringBuffer.append(chars[i]); + i++; + } + stringStack.push(stringBuffer.toString()); + inArray = true; + } + break; + case SIGC_VOID: + case SIGC_INT: + case SIGC_DOUBLE: + case SIGC_FLOAT: + case SIGC_SHORT: + case SIGC_CHAR: + case SIGC_BYTE: + case SIGC_LONG: + case SIGC_BOOLEAN: { + StringBuilder stringBuffer = null; + if (inArray) { + stringBuffer = new StringBuilder(stringStack.pop()); + } else { + stringBuffer = new StringBuilder(); + } + stringBuffer.append(chars[i]); + i++; // step over this + stringStack.push(stringBuffer.toString()); + inArray = false; + } + break; + case SIGC_START_METHOD: { + i++; // step over this + } + break; + case SIGC_END_METHOD: { + inMethod = true; + inArray = false; + methodStack = stringStack; + stringStack = new Stack<String>(); + i++; // step over this + } + break; + } + } + + if (inMethod) { + methodDescription = new MethodDescription(className, methodName, stringStack.toArray(new String[0])[0], + methodStack.toArray(new String[0])); + } else { + System.out.println("can't convert to a description"); + } + + return (methodDescription); + } + + private static final ValueCache<Class<?>, ClassModel, ClassParseException> classModelCache = ValueCache + .on(new ThrowingValueComputer<Class<?>, ClassModel, ClassParseException>(){ + @Override + public ClassModel compute(Class<?> key) throws ClassParseException { + return createClassModelInternal(key); + } + }); + + private static ClassModel createClassModelInternal(Class<?> key) throws ClassParseException { + ClassModel classModel = new ClassModel(key); + return classModel; + } + + public static ClassModel createClassModel(Class<?> _class) throws ClassParseException { + if (CacheEnabler.areCachesEnabled()) { + return classModelCache.computeIfAbsent(_class); + } + + return createClassModelInternal(_class); + } + + private int magic; + + private int minorVersion; + + private int majorVersion; + + private ConstantPool constantPool; + + private int accessFlags; + + private int thisClassConstantPoolIndex; + + private int superClassConstantPoolIndex; + + private final List<ClassModelInterface> interfaces = new ArrayList<ClassModelInterface>(); + + private final List<ClassModelField> fields = new ArrayList<ClassModelField>(); + + private final List<ClassModelMethod> methods = new ArrayList<ClassModelMethod>(); + + private AttributePool attributePool; + + public enum ConstantPoolType { + EMPTY, //0 + UTF8, //1 + UNICODE, //2 + INTEGER, //3 + FLOAT, //4 + LONG, //5 + DOUBLE, //6 + CLASS, //7 + STRING, //8 + FIELD, //9 + METHOD, //10 + INTERFACEMETHOD, //11 + NAMEANDTYPE, //12 + UNUSED13, + UNUSED14, + METHODHANDLE, //15 + METHODTYPE, //16 + UNUSED17, + INVOKEDYNAMIC//18 + }; + + public enum Access { + PUBLIC(0x00000001), + PRIVATE(0x00000002), + PROTECTED(0x00000004), + STATIC(0x00000008), + FINAL(0x00000010), + ACC_SYNCHRONIZED(0x00000020), + ACC_VOLATILE(0x00000040), + BRIDGE(0x00000040), + TRANSIENT(0x00000080), + VARARGS(0x00000080), + NATIVE(0x00000100), + INTERFACE(0x00000200), + ABSTRACT(0x00000400), + SUPER(0x00000020), + STRICT(0x00000800), + ANNOTATION(0x00002000), + ACC_ENUM(0x00004000); + int bits; + + private Access(int _bits) { + bits = _bits; + } + + public boolean bitIsSet(int _accessFlags) { + return ((bits & _accessFlags) == bits); + } + + public String convert(int _accessFlags) { + final StringBuffer stringBuffer = new StringBuffer(); + for (final Access access : Access.values()) { + if (access.bitIsSet(_accessFlags)) { + stringBuffer.append(" " + access.name().toLowerCase()); + } + } + + return (stringBuffer.toString()); + } + } + + private static enum SignatureParseState { + skipping, + counting, + inclass, + inArray, + done; + }; + + public class ConstantPool implements Iterable<ConstantPool.Entry>{ + + private final List<Entry> entries = new ArrayList<Entry>(); + + public abstract class Entry { + private final ConstantPoolType constantPoolType; + + private final int slot; + + public Entry(ByteReader _byteReader, int _slot, ConstantPoolType _constantPoolType) { + constantPoolType = _constantPoolType; + slot = _slot; + } + + public ConstantPoolType getConstantPoolType() { + return (constantPoolType); + } + + public int getSlot() { + return (slot); + } + + public ClassModel getOwnerClassModel() { + return ClassModel.this; + } + } + + public class ClassEntry extends Entry{ + private final int nameIndex; + + public ClassEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.CLASS); + nameIndex = _byteReader.u2(); + } + + public int getNameIndex() { + return (nameIndex); + } + + public UTF8Entry getNameUTF8Entry() { + return (getUTF8Entry(nameIndex)); + } + } + + public class DoubleEntry extends Entry{ + private final double doubleValue; + + public DoubleEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.DOUBLE); + doubleValue = _byteReader.d8(); + } + + public double getDoubleValue() { + return (doubleValue); + } + } + + public class EmptyEntry extends Entry{ + public EmptyEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.EMPTY); + } + } + + public class FieldEntry extends ReferenceEntry{ + public FieldEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.FIELD); + } + } + + public class FloatEntry extends Entry{ + private final float floatValue; + + public FloatEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.FLOAT); + floatValue = _byteReader.f4(); + } + + public float getFloatValue() { + return (floatValue); + } + } + + public class IntegerEntry extends Entry{ + private final int intValue; + + public IntegerEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.INTEGER); + intValue = _byteReader.u4(); + } + + public int getIntValue() { + return (intValue); + } + } + + public class InterfaceMethodEntry extends MethodReferenceEntry{ + InterfaceMethodEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.INTERFACEMETHOD); + } + } + + public class LongEntry extends Entry{ + private final long longValue; + + public LongEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.LONG); + longValue = _byteReader.u8(); + } + + public long getLongValue() { + return (longValue); + } + } + + public class MethodEntry extends MethodReferenceEntry{ + public MethodEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.METHOD); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append(getClassEntry().getNameUTF8Entry().getUTF8()); + sb.append("."); + sb.append(getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); + sb.append(getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8()); + return (sb.toString()); + } + } + + public class NameAndTypeEntry extends Entry{ + private final int descriptorIndex; + + private final int nameIndex; + + public NameAndTypeEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.NAMEANDTYPE); + nameIndex = _byteReader.u2(); + descriptorIndex = _byteReader.u2(); + } + + public int getDescriptorIndex() { + return (descriptorIndex); + } + + public UTF8Entry getDescriptorUTF8Entry() { + return (getUTF8Entry(descriptorIndex)); + } + + public int getNameIndex() { + return (nameIndex); + } + + public UTF8Entry getNameUTF8Entry() { + return (getUTF8Entry(nameIndex)); + } + } + + class MethodTypeEntry extends Entry{ + private int descriptorIndex; + + MethodTypeEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.METHODTYPE); + descriptorIndex = _byteReader.u2(); + } + + int getDescriptorIndex() { + return (descriptorIndex); + } + + UTF8Entry getDescriptorUTF8Entry() { + return (ConstantPool.this.getUTF8Entry(descriptorIndex)); + } + + } + + class MethodHandleEntry extends Entry{ + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4 + + private int referenceKind; + + private int referenceIndex; + + MethodHandleEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.METHODHANDLE); + referenceKind = _byteReader.u1(); + referenceIndex = _byteReader.u2(); + } + + int getReferenceIndex() { + return (referenceIndex); + } + + int getReferenceKind() { + return (referenceKind); + } + + } + + class InvokeDynamicEntry extends Entry{ + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4 + + private int bootstrapMethodAttrIndex; + + private int nameAndTypeIndex; + + InvokeDynamicEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.INVOKEDYNAMIC); + bootstrapMethodAttrIndex = _byteReader.u2(); + nameAndTypeIndex = _byteReader.u2(); + } + + int getBootstrapMethodAttrIndex() { + return (bootstrapMethodAttrIndex); + } + + int getNameAndTypeIndex() { + return (nameAndTypeIndex); + } + + } + + public abstract class MethodReferenceEntry extends ReferenceEntry{ + + public class Arg extends Type{ + Arg(String _signature, int _start, int _pos, int _argc) { + super(_signature.substring(_start, _pos + 1)); + argc = _argc; + } + + private final int argc; + + int getArgc() { + return (argc); + } + } + + private Arg[] args = null; + + private Type returnType = null; + + @Override + public int hashCode() { + final NameAndTypeEntry nameAndTypeEntry = getNameAndTypeEntry(); + + return ((((nameAndTypeEntry.getNameIndex() * 31) + nameAndTypeEntry.getDescriptorIndex()) * 31) + getClassIndex()); + } + + @Override + public boolean equals(Object _other) { + if ((_other == null) || !(_other instanceof MethodReferenceEntry)) { + return (false); + } else { + final MethodReferenceEntry otherMethodReferenceEntry = (MethodReferenceEntry) _other; + return ((otherMethodReferenceEntry.getNameAndTypeEntry().getNameIndex() == getNameAndTypeEntry().getNameIndex()) + && (otherMethodReferenceEntry.getNameAndTypeEntry().getDescriptorIndex() == getNameAndTypeEntry() + .getDescriptorIndex()) && (otherMethodReferenceEntry.getClassIndex() == getClassIndex())); + } + } + + public MethodReferenceEntry(ByteReader byteReader, int slot, ConstantPoolType constantPoolType) { + super(byteReader, slot, constantPoolType); + + } + + public int getStackProduceCount() { + return (getReturnType().isVoid() ? 0 : 1); + } + + public Type getReturnType() { + if (returnType == null) { + getArgs(); + } + + return (returnType); + } + + public Arg[] getArgs() { + if ((args == null) || (returnType == null)) { + final List<Arg> argList = new ArrayList<Arg>(); + final NameAndTypeEntry nameAndTypeEntry = getNameAndTypeEntry(); + + final String signature = nameAndTypeEntry.getDescriptorUTF8Entry().getUTF8();// "([[IF)V" for a method that takes an int[][], float and returns void. + // Sadly we need to parse this, we need the # of arguments for the call + SignatureParseState state = SignatureParseState.skipping; + int start = 0; + + for (int pos = 0; state != SignatureParseState.done; pos++) { + final char ch = signature.charAt(pos); + switch (ch) { + case '(': + state = SignatureParseState.counting; + break; + case ')': + state = SignatureParseState.done; + returnType = new Type(signature.substring(pos + 1)); + break; + case '[': + switch (state) { + case counting: + state = SignatureParseState.inArray; + start = pos; + break; + + } + // we don't care about arrays + break; + case 'L': + // beginning of Ljava/lang/String; or something + + switch (state) { + case counting: + start = pos; + // fallthrough intended!! + case inArray: + state = SignatureParseState.inclass; + break; + } + break; + case ';': + // note we will only be in 'inclass' if we were previously counting, so this is safe + switch (state) { + case inclass: + argList.add(new Arg(signature, start, pos, argList.size())); + state = SignatureParseState.counting; + break; + } + break; + + default: + // we have IJBZDF so inc counter if we are still counting + switch (state) { + case counting: + start = pos; + // fallthrough intended!! + case inArray: + argList.add(new Arg(signature, start, pos, argList.size())); + break; + + } + break; + } + } + // System.out.println("method "+name+" has signature of "+signature+" which has "+count+" args"); + + args = argList.toArray(new Arg[0]); + } + + return (args); + } + + public int getStackConsumeCount() { + return (getArgs().length); + } + } + + public abstract class ReferenceEntry extends Entry{ + protected int referenceClassIndex; + + protected int nameAndTypeIndex; + + protected int argCount = -1; + + public ReferenceEntry(ByteReader _byteReader, int _slot, ConstantPoolType _constantPoolType) { + super(_byteReader, _slot, _constantPoolType); + referenceClassIndex = _byteReader.u2(); + nameAndTypeIndex = _byteReader.u2(); + } + + public ClassEntry getClassEntry() { + return (ConstantPool.this.getClassEntry(referenceClassIndex)); + } + + public int getClassIndex() { + return (referenceClassIndex); + } + + public NameAndTypeEntry getNameAndTypeEntry() { + return (ConstantPool.this.getNameAndTypeEntry(nameAndTypeIndex)); + } + + public int getNameAndTypeIndex() { + return (nameAndTypeIndex); + } + + public boolean same(Entry _entry) { + if (_entry instanceof ReferenceEntry) { + final ReferenceEntry entry = (ReferenceEntry) _entry; + return ((referenceClassIndex == entry.referenceClassIndex) && (nameAndTypeIndex == entry.nameAndTypeIndex)); + } + + return (false); + } + + public class Type{ + private int arrayDimensions = 0; + + public Type(String _type) { + type = _type; + + while (type.charAt(arrayDimensions) == '[') { + arrayDimensions++; + } + type = type.substring(arrayDimensions); + } + + public String getType() { + return (type); + } + + public boolean isVoid() { + return (type.equals("V")); + } + + private String type; + + public boolean isArray() { + return (arrayDimensions > 0); + } + + public int getArrayDimensions() { + return (arrayDimensions); + } + } + } + + public class StringEntry extends Entry{ + private final int utf8Index; + + public StringEntry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.STRING); + utf8Index = _byteReader.u2(); + } + + public int getUTF8Index() { + return (utf8Index); + } + + public UTF8Entry getStringUTF8Entry() { + return (getUTF8Entry(utf8Index)); + } + } + + public class UTF8Entry extends Entry{ + private final String UTF8; + + public UTF8Entry(ByteReader _byteReader, int _slot) { + super(_byteReader, _slot, ConstantPoolType.UTF8); + UTF8 = _byteReader.utf8(); + } + + public String getUTF8() { + return (UTF8); + } + } + + public ConstantPool(ByteReader _byteReader) { + final int size = _byteReader.u2(); + add(new EmptyEntry(_byteReader, 0)); // slot 0 + + for (int i = 1; i < size; i++) { + final ConstantPoolType constantPoolType = ConstantPoolType.values()[_byteReader.u1()]; + + switch (constantPoolType) { + case UTF8: + add(new UTF8Entry(_byteReader, i)); + break; + case INTEGER: + add(new IntegerEntry(_byteReader, i)); + break; + case FLOAT: + add(new FloatEntry(_byteReader, i)); + break; + case LONG: + add(new LongEntry(_byteReader, i)); + i++;// Longs take two slots in the ConstantPool + add(new EmptyEntry(_byteReader, i)); + break; + case DOUBLE: + add(new DoubleEntry(_byteReader, i)); + i++; // Doubles take two slots in the ConstantPool + add(new EmptyEntry(_byteReader, i)); + break; + case CLASS: + add(new ClassEntry(_byteReader, i)); + break; + case STRING: + add(new StringEntry(_byteReader, i)); + break; + case FIELD: + add(new FieldEntry(_byteReader, i)); + break; + case METHOD: + add(new MethodEntry(_byteReader, i)); + break; + case INTERFACEMETHOD: + add(new InterfaceMethodEntry(_byteReader, i)); + break; + case NAMEANDTYPE: + add(new NameAndTypeEntry(_byteReader, i)); + break; + case METHODHANDLE: + add(new MethodHandleEntry(_byteReader, i)); + break; + case METHODTYPE: + add(new MethodTypeEntry(_byteReader, i)); + break; + case INVOKEDYNAMIC: + add(new InvokeDynamicEntry(_byteReader, i)); + break; + default: + System.out.printf("slot %04x unexpected Constant constantPoolType = %s\n", i, constantPoolType); + } + } + } + + public ClassEntry getClassEntry(int _index) { + try { + return ((ClassEntry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + public DoubleEntry getDoubleEntry(int _index) { + try { + return ((DoubleEntry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + public FieldEntry getFieldEntry(int _index) { + try { + return ((FieldEntry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + FieldEntry getFieldEntry(String _name) { + for (Entry entry : entries) { + if (entry instanceof FieldEntry) { + String fieldName = ((FieldEntry) entry).getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + if (_name.equals(fieldName)) { + return (FieldEntry) entry; + } + } + } + return null; + } + + public FloatEntry getFloatEntry(int _index) { + try { + return ((FloatEntry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + public IntegerEntry getIntegerEntry(int _index) { + try { + return ((IntegerEntry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + public InterfaceMethodEntry getInterfaceMethodEntry(int _index) { + try { + return ((InterfaceMethodEntry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + public LongEntry getLongEntry(int _index) { + try { + return ((LongEntry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + public MethodEntry getMethodEntry(int _index) { + try { + return ((MethodEntry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + public NameAndTypeEntry getNameAndTypeEntry(int _index) { + try { + return ((NameAndTypeEntry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + public StringEntry getStringEntry(int _index) { + try { + return ((StringEntry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + public UTF8Entry getUTF8Entry(int _index) { + try { + return ((UTF8Entry) entries.get(_index)); + } catch (final ClassCastException e) { + return (null); + } + } + + public void add(Entry _entry) { + entries.add(_entry); + + } + + @Override + public Iterator<Entry> iterator() { + return (entries.iterator()); + } + + public Entry get(int _index) { + return (entries.get(_index)); + } + + public String getDescription(ConstantPool.Entry _entry) { + final StringBuilder sb = new StringBuilder(); + if (_entry instanceof ConstantPool.EmptyEntry) { + ; + } else if (_entry instanceof ConstantPool.DoubleEntry) { + final ConstantPool.DoubleEntry doubleEntry = (ConstantPool.DoubleEntry) _entry; + sb.append(doubleEntry.getDoubleValue()); + } else if (_entry instanceof ConstantPool.FloatEntry) { + final ConstantPool.FloatEntry floatEntry = (ConstantPool.FloatEntry) _entry; + sb.append(floatEntry.getFloatValue()); + } else if (_entry instanceof ConstantPool.IntegerEntry) { + final ConstantPool.IntegerEntry integerEntry = (ConstantPool.IntegerEntry) _entry; + sb.append(integerEntry.getIntValue()); + } else if (_entry instanceof ConstantPool.LongEntry) { + final ConstantPool.LongEntry longEntry = (ConstantPool.LongEntry) _entry; + sb.append(longEntry.getLongValue()); + } else if (_entry instanceof ConstantPool.UTF8Entry) { + final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) _entry; + sb.append(utf8Entry.getUTF8()); + } else if (_entry instanceof ConstantPool.StringEntry) { + final ConstantPool.StringEntry stringEntry = (ConstantPool.StringEntry) _entry; + final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(stringEntry.getUTF8Index()); + sb.append(utf8Entry.getUTF8()); + } else if (_entry instanceof ConstantPool.ClassEntry) { + final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) _entry; + final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); + sb.append(utf8Entry.getUTF8()); + } else if (_entry instanceof ConstantPool.NameAndTypeEntry) { + final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) _entry; + final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); + final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); + sb.append(utf8NameEntry.getUTF8() + "." + utf8DescriptorEntry.getUTF8()); + } else if (_entry instanceof ConstantPool.MethodEntry) { + final ConstantPool.MethodEntry methodEntry = (ConstantPool.MethodEntry) _entry; + final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(methodEntry.getClassIndex()); + final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); + final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(methodEntry + .getNameAndTypeIndex()); + final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); + final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); + sb.append(convert(utf8DescriptorEntry.getUTF8(), utf8Entry.getUTF8() + "." + utf8NameEntry.getUTF8())); + } else if (_entry instanceof ConstantPool.InterfaceMethodEntry) { + final ConstantPool.InterfaceMethodEntry interfaceMethodEntry = (ConstantPool.InterfaceMethodEntry) _entry; + final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(interfaceMethodEntry.getClassIndex()); + final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); + final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(interfaceMethodEntry + .getNameAndTypeIndex()); + final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); + final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); + sb.append(convert(utf8DescriptorEntry.getUTF8(), utf8Entry.getUTF8() + "." + utf8NameEntry.getUTF8())); + } else if (_entry instanceof ConstantPool.FieldEntry) { + final ConstantPool.FieldEntry fieldEntry = (ConstantPool.FieldEntry) _entry; + final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(fieldEntry.getClassIndex()); + final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); + final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(fieldEntry + .getNameAndTypeIndex()); + final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); + final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); + sb.append(convert(utf8DescriptorEntry.getUTF8(), utf8Entry.getUTF8() + "." + utf8NameEntry.getUTF8())); + } + + return (sb.toString()); + } + + public int[] getConstantPoolReferences(ConstantPool.Entry _entry) { + int[] references = new int[0]; + if (_entry instanceof ConstantPool.StringEntry) { + final ConstantPool.StringEntry stringEntry = (ConstantPool.StringEntry) _entry; + references = new int[] { + stringEntry.getUTF8Index() + }; + } else if (_entry instanceof ConstantPool.ClassEntry) { + final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) _entry; + references = new int[] { + classEntry.getNameIndex() + }; + } else if (_entry instanceof ConstantPool.NameAndTypeEntry) { + final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) _entry; + references = new int[] { + nameAndTypeEntry.getNameIndex(), nameAndTypeEntry.getDescriptorIndex() + }; + } else if (_entry instanceof ConstantPool.MethodEntry) { + final ConstantPool.MethodEntry methodEntry = (ConstantPool.MethodEntry) _entry; + final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(methodEntry.getClassIndex()); + @SuppressWarnings("unused") + final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); + final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(methodEntry + .getNameAndTypeIndex()); + @SuppressWarnings("unused") + final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); + @SuppressWarnings("unused") + final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); + references = new int[] { + methodEntry.getClassIndex(), classEntry.getNameIndex(), nameAndTypeEntry.getNameIndex(), + nameAndTypeEntry.getDescriptorIndex() + }; + } else if (_entry instanceof ConstantPool.InterfaceMethodEntry) { + final ConstantPool.InterfaceMethodEntry interfaceMethodEntry = (ConstantPool.InterfaceMethodEntry) _entry; + final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(interfaceMethodEntry.getClassIndex()); + @SuppressWarnings("unused") + final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); + final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(interfaceMethodEntry + .getNameAndTypeIndex()); + @SuppressWarnings("unused") + final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); + @SuppressWarnings("unused") + final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); + references = new int[] { + interfaceMethodEntry.getClassIndex(), classEntry.getNameIndex(), nameAndTypeEntry.getNameIndex(), + nameAndTypeEntry.getDescriptorIndex() + }; + } else if (_entry instanceof ConstantPool.FieldEntry) { + final ConstantPool.FieldEntry fieldEntry = (ConstantPool.FieldEntry) _entry; + final ConstantPool.ClassEntry classEntry = (ConstantPool.ClassEntry) get(fieldEntry.getClassIndex()); + @SuppressWarnings("unused") + final ConstantPool.UTF8Entry utf8Entry = (ConstantPool.UTF8Entry) get(classEntry.getNameIndex()); + final ConstantPool.NameAndTypeEntry nameAndTypeEntry = (ConstantPool.NameAndTypeEntry) get(fieldEntry + .getNameAndTypeIndex()); + @SuppressWarnings("unused") + final ConstantPool.UTF8Entry utf8NameEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getNameIndex()); + @SuppressWarnings("unused") + final ConstantPool.UTF8Entry utf8DescriptorEntry = (ConstantPool.UTF8Entry) get(nameAndTypeEntry.getDescriptorIndex()); + references = new int[] { + fieldEntry.getClassIndex(), classEntry.getNameIndex(), nameAndTypeEntry.getNameIndex(), + nameAndTypeEntry.getDescriptorIndex() + }; + } + + return (references); + } + + public String getType(ConstantPool.Entry _entry) { + final StringBuffer sb = new StringBuffer(); + if (_entry instanceof ConstantPool.EmptyEntry) { + sb.append("empty"); + } else if (_entry instanceof ConstantPool.DoubleEntry) { + sb.append("double"); + } else if (_entry instanceof ConstantPool.FloatEntry) { + sb.append("float"); + } else if (_entry instanceof ConstantPool.IntegerEntry) { + sb.append("int"); + } else if (_entry instanceof ConstantPool.LongEntry) { + sb.append("long"); + } else if (_entry instanceof ConstantPool.UTF8Entry) { + sb.append("utf8"); + } else if (_entry instanceof ConstantPool.StringEntry) { + sb.append("string"); + } else if (_entry instanceof ConstantPool.ClassEntry) { + sb.append("class"); + } else if (_entry instanceof ConstantPool.NameAndTypeEntry) { + sb.append("name/type"); + } else if (_entry instanceof ConstantPool.MethodEntry) { + sb.append("method"); + } else if (_entry instanceof ConstantPool.InterfaceMethodEntry) { + sb.append("interface method"); + } else if (_entry instanceof ConstantPool.FieldEntry) { + sb.append("field"); + } + + return (sb.toString()); + } + + public Object getConstantEntry(int _constantPoolIndex) { + final Entry entry = get(_constantPoolIndex); + Object object = null; + switch (entry.getConstantPoolType()) { + case FLOAT: + object = ((FloatEntry) entry).getFloatValue(); + break; + case DOUBLE: + object = ((DoubleEntry) entry).getDoubleValue(); + break; + case INTEGER: + object = ((IntegerEntry) entry).getIntValue(); + break; + case LONG: + object = ((LongEntry) entry).getLongValue(); + break; + case STRING: + object = ((StringEntry) entry).getStringUTF8Entry().getUTF8(); + break; + } + + return (object); + } + } + + public class AttributePool { + private final List<AttributePoolEntry> attributePoolEntries = new ArrayList<AttributePoolEntry>(); + + public class CodeEntry extends AttributePoolEntry{ + + public class ExceptionPoolEntry{ + private final int exceptionClassIndex; + + private final int end; + + private final int handler; + + private final int start; + + public ExceptionPoolEntry(ByteReader _byteReader) { + start = _byteReader.u2(); + end = _byteReader.u2(); + handler = _byteReader.u2(); + exceptionClassIndex = _byteReader.u2(); + } + + public ConstantPool.ClassEntry getClassEntry() { + return (constantPool.getClassEntry(exceptionClassIndex)); + } + + public int getClassIndex() { + return (exceptionClassIndex); + } + + public int getEnd() { + return (end); + } + + public int getHandler() { + return (handler); + } + + public int getStart() { + return (start); + } + } + + private final List<ExceptionPoolEntry> exceptionPoolEntries = new ArrayList<ExceptionPoolEntry>(); + + private final AttributePool codeEntryAttributePool; + + private final byte[] code; + + private final int maxLocals; + + private final int maxStack; + + public CodeEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + maxStack = _byteReader.u2(); + maxLocals = _byteReader.u2(); + final int codeLength = _byteReader.u4(); + code = _byteReader.bytes(codeLength); + final int exceptionTableLength = _byteReader.u2(); + + for (int i = 0; i < exceptionTableLength; i++) { + exceptionPoolEntries.add(new ExceptionPoolEntry(_byteReader)); + } + + codeEntryAttributePool = new AttributePool(_byteReader, getName()); + } + + @Override + public AttributePool getAttributePool() { + return (codeEntryAttributePool); + } + + public LineNumberTableEntry getLineNumberTableEntry() { + return (codeEntryAttributePool.getLineNumberTableEntry()); + } + + public int getMaxLocals() { + return (maxLocals); + } + + public int getMaxStack() { + return (maxStack); + } + + public byte[] getCode() { + return code; + } + + public List<ExceptionPoolEntry> getExceptionPoolEntries() { + return exceptionPoolEntries; + } + } + + public class ConstantValueEntry extends AttributePoolEntry{ + private final int index; + + public ConstantValueEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + index = _byteReader.u2(); + } + + public int getIndex() { + return (index); + } + + } + + public class DeprecatedEntry extends AttributePoolEntry{ + public DeprecatedEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + } + } + + public abstract class AttributePoolEntry { + protected int length; + + protected int nameIndex; + + public AttributePoolEntry(ByteReader _byteReader, int _nameIndex, int _length) { + nameIndex = _nameIndex; + length = _length; + } + + public AttributePool getAttributePool() { + return (null); + } + + public int getLength() { + return (length); + } + + public String getName() { + return (constantPool.getUTF8Entry(nameIndex).getUTF8()); + } + + public int getNameIndex() { + return (nameIndex); + } + } + + public abstract class PoolEntry<T> extends AttributePoolEntry implements Iterable<T>{ + private final List<T> pool = new ArrayList<T>(); + + public List<T> getPool() { + return (pool); + } + + public PoolEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + } + + @Override + public Iterator<T> iterator() { + return (pool.iterator()); + } + } + + public class ExceptionEntry extends PoolEntry<Integer>{ + public ExceptionEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + final int exceptionTableLength = _byteReader.u2(); + for (int i = 0; i < exceptionTableLength; i++) { + getPool().add(_byteReader.u2()); + } + } + } + + public class InnerClassesEntry extends PoolEntry<InnerClassesEntry.InnerClassInfo>{ + public class InnerClassInfo { + private final int innerAccess; + + private final int innerIndex; + + private final int innerNameIndex; + + private final int outerIndex; + + public InnerClassInfo(ByteReader _byteReader) { + innerIndex = _byteReader.u2(); + outerIndex = _byteReader.u2(); + innerNameIndex = _byteReader.u2(); + innerAccess = _byteReader.u2(); + } + + public int getInnerAccess() { + return (innerAccess); + } + + public int getInnerIndex() { + return (innerIndex); + } + + public int getInnerNameIndex() { + return (innerNameIndex); + } + + public int getOuterIndex() { + return (outerIndex); + } + } + + public InnerClassesEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + final int innerClassesTableLength = _byteReader.u2(); + for (int i = 0; i < innerClassesTableLength; i++) { + getPool().add(new InnerClassInfo(_byteReader)); + } + } + } + + public class LineNumberTableEntry extends PoolEntry<LineNumberTableEntry.StartLineNumberPair>{ + + public class StartLineNumberPair { + private final int lineNumber; + + private final int start; + + public StartLineNumberPair(ByteReader _byteReader) { + start = _byteReader.u2(); + lineNumber = _byteReader.u2(); + } + + public int getLineNumber() { + return (lineNumber); + } + + public int getStart() { + return (start); + } + } + + public LineNumberTableEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + final int lineNumberTableLength = _byteReader.u2(); + for (int i = 0; i < lineNumberTableLength; i++) { + getPool().add(new StartLineNumberPair(_byteReader)); + } + } + + public int getSourceLineNumber(int _start, boolean _exact) { + final Iterator<StartLineNumberPair> i = getPool().iterator(); + if (i.hasNext()) { + StartLineNumberPair from = i.next(); + while (i.hasNext()) { + final StartLineNumberPair to = i.next(); + if (_exact) { + if (_start == from.getStart()) { + return (from.getLineNumber()); + } + } else if ((_start >= from.getStart()) && (_start < to.getStart())) { + return (from.getLineNumber()); + } + from = to; + } + if (_exact) { + if (_start == from.getStart()) { + return (from.getLineNumber()); + } + } else if (_start >= from.getStart()) { + return (from.getLineNumber()); + } + } + + return (-1); + } + } + + public class EnclosingMethodEntry extends AttributePoolEntry{ + + public EnclosingMethodEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + enclosingClassIndex = _byteReader.u2(); + enclosingMethodIndex = _byteReader.u2(); + } + + private final int enclosingClassIndex; + + public int getClassIndex() { + return (enclosingClassIndex); + } + + private final int enclosingMethodIndex; + + public int getMethodIndex() { + return (enclosingMethodIndex); + } + } + + public class SignatureEntry extends AttributePoolEntry{ + + public SignatureEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + signatureIndex = _byteReader.u2(); + } + + private final int signatureIndex; + + int getSignatureIndex() { + return (signatureIndex); + } + } + + public class RealLocalVariableTableEntry extends PoolEntry<RealLocalVariableTableEntry.RealLocalVariableInfo> implements + LocalVariableTableEntry<RealLocalVariableTableEntry.RealLocalVariableInfo>{ + + class RealLocalVariableInfo implements LocalVariableInfo{ + private final int descriptorIndex; + + private final int usageLength; + + private final int variableNameIndex; + + private final int start; + + private final int variableIndex; + + public RealLocalVariableInfo(ByteReader _byteReader) { + start = _byteReader.u2(); + usageLength = _byteReader.u2(); + variableNameIndex = _byteReader.u2(); + descriptorIndex = _byteReader.u2(); + variableIndex = _byteReader.u2(); + } + + public int getDescriptorIndex() { + return (descriptorIndex); + } + + public int getLength() { + return (usageLength); + } + + public int getNameIndex() { + return (variableNameIndex); + } + + @Override + public int getStart() { + return (start); + } + + @Override + public int getVariableIndex() { + return (variableIndex); + } + + @Override + public String getVariableName() { + return (constantPool.getUTF8Entry(variableNameIndex).getUTF8()); + } + + @Override + public String getVariableDescriptor() { + return (constantPool.getUTF8Entry(descriptorIndex).getUTF8()); + } + + @Override + public int getEnd() { + return (start + usageLength); + } + + @Override + public boolean isArray() { + return (getVariableDescriptor().startsWith("[")); + } + } + + public RealLocalVariableTableEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + final int localVariableTableLength = _byteReader.u2(); + for (int i = 0; i < localVariableTableLength; i++) { + getPool().add(new RealLocalVariableInfo(_byteReader)); + } + } + + public RealLocalVariableInfo getVariable(int _pc, int _index) { + RealLocalVariableInfo returnValue = null; + // System.out.println("pc = " + _pc + " index = " + _index); + for (final RealLocalVariableInfo localVariableInfo : getPool()) { + // System.out.println(" start=" + localVariableInfo.getStart() + " length=" + localVariableInfo.getLength() + // + " varidx=" + localVariableInfo.getVariableIndex()); + if ((_pc >= (localVariableInfo.getStart() - 1)) + && (_pc <= (localVariableInfo.getStart() + localVariableInfo.getLength())) + && (_index == localVariableInfo.getVariableIndex())) { + returnValue = localVariableInfo; + break; + } + } + + // System.out.println("returning " + returnValue); + return (returnValue); + } + + public String getVariableName(int _pc, int _index) { + String returnValue = "unknown"; + final RealLocalVariableInfo localVariableInfo = (RealLocalVariableInfo) getVariable(_pc, _index); + if (localVariableInfo != null) { + returnValue = convert(constantPool.getUTF8Entry(localVariableInfo.getDescriptorIndex()).getUTF8(), constantPool + .getUTF8Entry(localVariableInfo.getNameIndex()).getUTF8()); + } + // System.out.println("returning " + returnValue); + return (returnValue); + } + } + + class BootstrapMethodsEntry extends AttributePoolEntry{ + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.21 + class BootstrapMethod{ + class BootstrapArgument{ + public BootstrapArgument(ByteReader _byteReader) { + argument = _byteReader.u2(); + } + + int argument;// u2; + } + + public BootstrapMethod(ByteReader _byteReader) { + bootstrapMethodRef = _byteReader.u2(); + numBootstrapArguments = _byteReader.u2(); + bootstrapArguments = new BootstrapArgument[numBootstrapArguments]; + for (int i = 0; i < numBootstrapArguments; i++) { + bootstrapArguments[i] = new BootstrapArgument(_byteReader); + } + } + + int bootstrapMethodRef; //u2 + + int numBootstrapArguments; //u2 + + BootstrapArgument bootstrapArguments[]; + } + + BootstrapMethodsEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + numBootstrapMethods = _byteReader.u2(); + bootstrapMethods = new BootstrapMethod[numBootstrapMethods]; + for (int i = 0; i < numBootstrapMethods; i++) { + bootstrapMethods[i] = new BootstrapMethod(_byteReader); + } + } + + private int numBootstrapMethods; + + BootstrapMethod bootstrapMethods[]; + + int getNumBootstrapMethods() { + return (numBootstrapMethods); + } + + } + + public class OtherEntry extends AttributePoolEntry{ + private final byte[] bytes; + + public OtherEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + bytes = _byteReader.bytes(_length); + } + + public byte[] getBytes() { + return (bytes); + } + + @Override + public String toString() { + return (new String(bytes)); + } + + } + + class StackMapTableEntry extends AttributePoolEntry{ + private byte[] bytes; + + StackMapTableEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + bytes = _byteReader.bytes(_length); + } + + byte[] getBytes() { + return (bytes); + } + + @Override + public String toString() { + return (new String(bytes)); + } + } + + public class LocalVariableTypeTableEntry extends AttributePoolEntry{ + private byte[] bytes; + + public LocalVariableTypeTableEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + bytes = _byteReader.bytes(_length); + } + + public byte[] getBytes() { + return (bytes); + } + + @Override + public String toString() { + return (new String(bytes)); + } + } + + public class SourceFileEntry extends AttributePoolEntry{ + private final int sourceFileIndex; + + public SourceFileEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + sourceFileIndex = _byteReader.u2(); + } + + public int getSourceFileIndex() { + return (sourceFileIndex); + } + + public String getSourceFileName() { + return (constantPool.getUTF8Entry(sourceFileIndex).getUTF8()); + } + } + + public class SyntheticEntry extends AttributePoolEntry{ + public SyntheticEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + } + } + + public class RuntimeAnnotationsEntry extends PoolEntry<RuntimeAnnotationsEntry.AnnotationInfo>{ + + public class AnnotationInfo { + private final int typeIndex; + + private final int elementValuePairCount; + + public class ElementValuePair{ + class Value { + Value(int _tag) { + tag = _tag; + } + + int tag; + + } + + public class PrimitiveValue extends Value{ + private final int typeNameIndex; + + private final int constNameIndex; + + public PrimitiveValue(int _tag, ByteReader _byteReader) { + super(_tag); + typeNameIndex = _byteReader.u2(); + //constNameIndex = _byteReader.u2(); + constNameIndex = 0; + } + + public int getConstNameIndex() { + return (constNameIndex); + } + + public int getTypeNameIndex() { + return (typeNameIndex); + } + } + + public class EnumValue extends Value{ + EnumValue(int _tag, ByteReader _byteReader) { + super(_tag); + } + } + + public class ArrayValue extends Value{ + ArrayValue(int _tag, ByteReader _byteReader) { + super(_tag); + } + } + + public class ClassValue extends Value{ + ClassValue(int _tag, ByteReader _byteReader) { + super(_tag); + } + } + + public class AnnotationValue extends Value{ + AnnotationValue(int _tag, ByteReader _byteReader) { + super(_tag); + } + } + + @SuppressWarnings("unused") + private final int elementNameIndex; + + @SuppressWarnings("unused") + private Value value; + + public ElementValuePair(ByteReader _byteReader) { + elementNameIndex = _byteReader.u2(); + final int tag = _byteReader.u1(); + + switch (tag) { + case SIGC_BYTE: + case SIGC_CHAR: + case SIGC_INT: + case SIGC_LONG: + case SIGC_DOUBLE: + case SIGC_FLOAT: + case SIGC_SHORT: + case SIGC_BOOLEAN: + case 's': // special for String + value = new PrimitiveValue(tag, _byteReader); + break; + case 'e': // special for Enum + value = new EnumValue(tag, _byteReader); + break; + case 'c': // special for class + value = new ClassValue(tag, _byteReader); + break; + case '@': // special for Annotation + value = new AnnotationValue(tag, _byteReader); + break; + case 'a': // special for array + value = new ArrayValue(tag, _byteReader); + break; + } + } + } + + private final ElementValuePair[] elementValuePairs; + + public AnnotationInfo(ByteReader _byteReader) { + typeIndex = _byteReader.u2(); + elementValuePairCount = _byteReader.u2(); + elementValuePairs = new ElementValuePair[elementValuePairCount]; + for (int i = 0; i < elementValuePairCount; i++) { + elementValuePairs[i] = new ElementValuePair(_byteReader); + } + } + + public int getTypeIndex() { + return (typeIndex); + } + + public String getTypeDescriptor() { + return (constantPool.getUTF8Entry(typeIndex).getUTF8()); + } + } + + public RuntimeAnnotationsEntry(ByteReader _byteReader, int _nameIndex, int _length) { + super(_byteReader, _nameIndex, _length); + final int localVariableTableLength = _byteReader.u2(); + for (int i = 0; i < localVariableTableLength; i++) { + getPool().add(new AnnotationInfo(_byteReader)); + } + } + + } + + private CodeEntry codeEntry = null; + + private EnclosingMethodEntry enclosingMethodEntry = null; + + private DeprecatedEntry deprecatedEntry = null; + + private ExceptionEntry exceptionEntry = null; + + private LineNumberTableEntry lineNumberTableEntry = null; + + private LocalVariableTableEntry localVariableTableEntry = null; + + private RuntimeAnnotationsEntry runtimeVisibleAnnotationsEntry; + + private RuntimeAnnotationsEntry runtimeInvisibleAnnotationsEntry; + + private SourceFileEntry sourceFileEntry = null; + + private SyntheticEntry syntheticEntry = null; + + private BootstrapMethodsEntry bootstrapMethodsEntry = null; + + private final static String LOCALVARIABLETABLE_TAG = "LocalVariableTable"; + + private final static String CONSTANTVALUE_TAG = "ConstantValue"; + + private final static String LINENUMBERTABLE_TAG = "LineNumberTable"; + + private final static String SOURCEFILE_TAG = "SourceFile"; + + private final static String SYNTHETIC_TAG = "Synthetic"; + + private final static String EXCEPTIONS_TAG = "Exceptions"; + + private final static String INNERCLASSES_TAG = "InnerClasses"; + + private final static String DEPRECATED_TAG = "Deprecated"; + + private final static String CODE_TAG = "Code"; + + private final static String ENCLOSINGMETHOD_TAG = "EnclosingMethod"; + + private final static String SIGNATURE_TAG = "Signature"; + + private final static String RUNTIMEINVISIBLEANNOTATIONS_TAG = "RuntimeInvisibleAnnotations"; + + private final static String RUNTIMEVISIBLEANNOTATIONS_TAG = "RuntimeVisibleAnnotations"; + + private final static String BOOTSTRAPMETHODS_TAG = "BootstrapMethods"; + + private final static String STACKMAPTABLE_TAG = "StackMapTable"; + + private final static String LOCALVARIABLETYPETABLE_TAG = "LocalVariableTypeTable"; + + public AttributePool(ByteReader _byteReader, String name) { + final int attributeCount = _byteReader.u2(); + AttributePoolEntry entry = null; + for (int i = 0; i < attributeCount; i++) { + final int attributeNameIndex = _byteReader.u2(); + final int length = _byteReader.u4(); + UTF8Entry utf8Entry = constantPool.getUTF8Entry(attributeNameIndex); + if (utf8Entry == null) { + throw new IllegalStateException("corrupted state reading attributes for " + name); + } + final String attributeName = utf8Entry.getUTF8(); + if (attributeName.equals(LOCALVARIABLETABLE_TAG)) { + localVariableTableEntry = new RealLocalVariableTableEntry(_byteReader, attributeNameIndex, length); + entry = (RealLocalVariableTableEntry) localVariableTableEntry; + } else if (attributeName.equals(CONSTANTVALUE_TAG)) { + entry = new ConstantValueEntry(_byteReader, attributeNameIndex, length); + } else if (attributeName.equals(LINENUMBERTABLE_TAG)) { + lineNumberTableEntry = new LineNumberTableEntry(_byteReader, attributeNameIndex, length); + entry = lineNumberTableEntry; + } else if (attributeName.equals(SOURCEFILE_TAG)) { + sourceFileEntry = new SourceFileEntry(_byteReader, attributeNameIndex, length); + entry = sourceFileEntry; + } else if (attributeName.equals(SYNTHETIC_TAG)) { + syntheticEntry = new SyntheticEntry(_byteReader, attributeNameIndex, length); + entry = syntheticEntry; + } else if (attributeName.equals(EXCEPTIONS_TAG)) { + exceptionEntry = new ExceptionEntry(_byteReader, attributeNameIndex, length); + entry = exceptionEntry; + } else if (attributeName.equals(INNERCLASSES_TAG)) { + entry = new InnerClassesEntry(_byteReader, attributeNameIndex, length); + } else if (attributeName.equals(DEPRECATED_TAG)) { + deprecatedEntry = new DeprecatedEntry(_byteReader, attributeNameIndex, length); + entry = deprecatedEntry; + } else if (attributeName.equals(CODE_TAG)) { + codeEntry = new CodeEntry(_byteReader, attributeNameIndex, length); + entry = codeEntry; + } else if (attributeName.equals(ENCLOSINGMETHOD_TAG)) { + enclosingMethodEntry = new EnclosingMethodEntry(_byteReader, attributeNameIndex, length); + entry = enclosingMethodEntry; + } else if (attributeName.equals(SIGNATURE_TAG)) { + entry = new SignatureEntry(_byteReader, attributeNameIndex, length); + } else if (attributeName.equals(RUNTIMEINVISIBLEANNOTATIONS_TAG)) { + runtimeInvisibleAnnotationsEntry = new RuntimeAnnotationsEntry(_byteReader, attributeNameIndex, length); + entry = runtimeInvisibleAnnotationsEntry; + } else if (attributeName.equals(RUNTIMEVISIBLEANNOTATIONS_TAG)) { + runtimeVisibleAnnotationsEntry = new RuntimeAnnotationsEntry(_byteReader, attributeNameIndex, length); + entry = runtimeVisibleAnnotationsEntry; + } else if (attributeName.equals(BOOTSTRAPMETHODS_TAG)) { + bootstrapMethodsEntry = new BootstrapMethodsEntry(_byteReader, attributeNameIndex, length); + entry = bootstrapMethodsEntry; + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.21 + } else if (attributeName.equals(STACKMAPTABLE_TAG)) { + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.4 + + entry = new StackMapTableEntry(_byteReader, attributeNameIndex, length); + } else if (attributeName.equals(LOCALVARIABLETYPETABLE_TAG)) { + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.14 + entry = new LocalVariableTypeTableEntry(_byteReader, attributeNameIndex, length); + } else { + logger.warning("Found unexpected Attribute (name = " + attributeName + ")"); + entry = new OtherEntry(_byteReader, attributeNameIndex, length); + } + attributePoolEntries.add(entry); + + } + } + + public CodeEntry getCodeEntry() { + return (codeEntry); + } + + public DeprecatedEntry getDeprecatedEntry() { + return (deprecatedEntry); + } + + public ExceptionEntry getExceptionEntry() { + return (exceptionEntry); + } + + public LineNumberTableEntry getLineNumberTableEntry() { + return (lineNumberTableEntry); + } + + public LocalVariableTableEntry getLocalVariableTableEntry() { + return (localVariableTableEntry); + } + + public SourceFileEntry getSourceFileEntry() { + return (sourceFileEntry); + } + + public SyntheticEntry getSyntheticEntry() { + return (syntheticEntry); + } + + public RuntimeAnnotationsEntry getRuntimeInvisibleAnnotationsEntry() { + return (runtimeInvisibleAnnotationsEntry); + } + + public RuntimeAnnotationsEntry getRuntimeVisibleAnnotationsEntry() { + return (runtimeVisibleAnnotationsEntry); + } + + public RuntimeAnnotationsEntry getBootstrap() { + return (runtimeVisibleAnnotationsEntry); + } + + } + + private static ClassLoader classModelLoader = ClassModel.class.getClassLoader(); + + public class ClassModelField { + private final int fieldAccessFlags; + + AttributePool fieldAttributePool; + + private final int descriptorIndex; + + private final int index; + + private final int nameIndex; + + public ClassModelField(ByteReader _byteReader, int _index) { + index = _index; + fieldAccessFlags = _byteReader.u2(); + nameIndex = _byteReader.u2(); + descriptorIndex = _byteReader.u2(); + fieldAttributePool = new AttributePool(_byteReader, getName()); + } + + public int getAccessFlags() { + return (fieldAccessFlags); + } + + public AttributePool getAttributePool() { + return (fieldAttributePool); + } + + public String getDescriptor() { + return (getDescriptorUTF8Entry().getUTF8()); + } + + public int getDescriptorIndex() { + return (descriptorIndex); + } + + public ConstantPool.UTF8Entry getDescriptorUTF8Entry() { + return (constantPool.getUTF8Entry(descriptorIndex)); + } + + public int getIndex() { + return (index); + } + + public String getName() { + return (getNameUTF8Entry().getUTF8()); + } + + public int getNameIndex() { + return (nameIndex); + } + + public ConstantPool.UTF8Entry getNameUTF8Entry() { + return (constantPool.getUTF8Entry(nameIndex)); + } + + public Class<?> getDeclaringClass() { + final String clazzName = getDescriptor().replaceAll("^L", "").replaceAll("/", ".").replaceAll(";$", ""); + try { + return (Class.forName(clazzName, true, classModelLoader)); + } catch (final ClassNotFoundException e) { + System.out.println("no class found for " + clazzName); + e.printStackTrace(); + return null; + } + } + } + + public class ClassModelMethod { + + private final int methodAccessFlags; + + private final AttributePool methodAttributePool; + + private final int descriptorIndex; + + private final int index; + + private final int nameIndex; + + private final CodeEntry codeEntry; + + public ClassModelMethod(ByteReader _byteReader, int _index) { + index = _index; + methodAccessFlags = _byteReader.u2(); + nameIndex = _byteReader.u2(); + descriptorIndex = _byteReader.u2(); + methodAttributePool = new AttributePool(_byteReader, getName()); + codeEntry = methodAttributePool.getCodeEntry(); + } + + public int getAccessFlags() { + return (methodAccessFlags); + } + + public boolean isStatic() { + return (Access.STATIC.bitIsSet(methodAccessFlags)); + } + + public AttributePool getAttributePool() { + return (methodAttributePool); + } + + public AttributePool.CodeEntry getCodeEntry() { + return (methodAttributePool.getCodeEntry()); + } + + public String getDescriptor() { + return (getDescriptorUTF8Entry().getUTF8()); + } + + public int getDescriptorIndex() { + return (descriptorIndex); + } + + public ConstantPool.UTF8Entry getDescriptorUTF8Entry() { + return (constantPool.getUTF8Entry(descriptorIndex)); + } + + public int getIndex() { + return (index); + } + + public String getName() { + return (getNameUTF8Entry().getUTF8()); + } + + public int getNameIndex() { + return (nameIndex); + } + + public ConstantPool.UTF8Entry getNameUTF8Entry() { + return (constantPool.getUTF8Entry(nameIndex)); + } + + public ConstantPool getConstantPool() { + return (constantPool); + } + + public AttributePool.LineNumberTableEntry getLineNumberTableEntry() { + return (getAttributePool().codeEntry.codeEntryAttributePool.lineNumberTableEntry); + } + + public LocalVariableTableEntry getLocalVariableTableEntry() { + return (getAttributePool().codeEntry.codeEntryAttributePool.localVariableTableEntry); + } + + void setLocalVariableTableEntry(LocalVariableTableEntry _localVariableTableEntry) { + getAttributePool().codeEntry.codeEntryAttributePool.localVariableTableEntry = _localVariableTableEntry; + } + + public LocalVariableInfo getLocalVariable(int _pc, int _index) { + return (getLocalVariableTableEntry().getVariable(_pc, _index)); + } + + public byte[] getCode() { + return (codeEntry.getCode()); + } + + public ClassModel getClassModel() { + return (ClassModel.this); + } + + public String toString() { + return getClassModel().getClassWeAreModelling().getName() + "." + getName() + " " + getDescriptor(); + } + + public ClassModel getOwnerClassModel() { + return ClassModel.this; + } + } + + public class ClassModelInterface { + private final int interfaceIndex; + + ClassModelInterface(ByteReader _byteReader) { + interfaceIndex = _byteReader.u2(); + } + + ConstantPool.ClassEntry getClassEntry() { + return (constantPool.getClassEntry(interfaceIndex)); + } + + int getInterfaceIndex() { + return (interfaceIndex); + } + + } + + private Class<?> clazz; + + /** + * We extract the class's classloader and name and delegate to private parse method. + * @param _class The class we wish to model + * @throws ClassParseException + */ + public void parse(Class<?> _class) throws ClassParseException { + + clazz = _class; + parse(_class.getClassLoader(), _class.getName()); + } + + /** + * Populate this model by parsing a given classfile from the given classloader. + * + * We create a ByteReader (wrapper around the bytes representing the classfile) and pass it to local inner classes to handle the various sections of the class file. + * + * @see ByteReader + * @see <a href="http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf">Java 5 Class File Format</a> + * @param _classLoader The classloader to access the classfile + * @param _className The name of the class to load (we convert '.' to '/' and append ".class" so you don't have to). + * @throws ClassParseException + */ + private void parse(ClassLoader _classLoader, String _className) throws ClassParseException { + + parse(_classLoader.getResourceAsStream(_className.replace('.', '/') + ".class")); + } + + void parse(InputStream _inputStream) throws ClassParseException { + + ByteReader byteReader = new ByteReader(_inputStream); + magic = byteReader.u4(); + minorVersion = byteReader.u2(); + majorVersion = byteReader.u2(); + constantPool = new ConstantPool(byteReader); + + accessFlags = byteReader.u2(); + thisClassConstantPoolIndex = byteReader.u2(); + superClassConstantPoolIndex = byteReader.u2(); + + final int interfaceCount = byteReader.u2(); + for (int i = 0; i < interfaceCount; i++) { + final ClassModelInterface iface = new ClassModelInterface(byteReader); + interfaces.add(iface); + } + + final int fieldCount = byteReader.u2(); + for (int i = 0; i < fieldCount; i++) { + final ClassModelField field = new ClassModelField(byteReader, i); + fields.add(field); + } + + final int methodPoolLength = byteReader.u2(); + for (int i = 0; i < methodPoolLength; i++) { + final ClassModelMethod method = new ClassModelMethod(byteReader, i); + methods.add(method); + } + + attributePool = new AttributePool(byteReader, Reflection.getSimpleName(getClassWeAreModelling())); + } + + public int getMagic() { + return (magic); + } + + public int getMajorVersion() { + return (majorVersion); + } + + public int getMinorVersion() { + return (minorVersion); + } + + public int getAccessFlags() { + return (accessFlags); + } + + public ConstantPool getConstantPool() { + return (constantPool); + } + + public int getThisClassConstantPoolIndex() { + return (thisClassConstantPoolIndex); + } + + public int getSuperClassConstantPoolIndex() { + return (superClassConstantPoolIndex); + } + + public AttributePool getAttributePool() { + return (attributePool); + } + + public ClassModelField getField(String _name, String _descriptor) { + for (final ClassModelField entry : fields) { + if (entry.getName().equals(_name) && entry.getDescriptor().equals(_descriptor)) { + return (entry); + } + } + return superClazz.getField(_name, _descriptor); + } + + public ClassModelField getField(String _name) { + for (final ClassModelField entry : fields) { + if (entry.getName().equals(_name)) { + return (entry); + } + } + return superClazz.getField(_name); + } + + public ClassModelMethod getMethod(String _name, String _descriptor) { + ClassModelMethod methodOrNull = getMethodOrNull(_name, _descriptor); + if (methodOrNull == null) + return superClazz != null ? superClazz.getMethod(_name, _descriptor) : (null); + return methodOrNull; + } + + private ClassModelMethod getMethodOrNull(String _name, String _descriptor) { + for (final ClassModelMethod entry : methods) { + if (entry.getName().equals(_name) && entry.getDescriptor().equals(_descriptor)) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Found " + clazz.getName() + "." + entry.getName() + " " + entry.getDescriptor() + " for " + + _name.replace('/', '.')); + } + return (entry); + } + } + return null; + } + + public List<ClassModelField> getFieldPoolEntries() { + return (fields); + } + + /** + * Look up a ConstantPool MethodEntry and return the corresponding Method. + * + * @param _methodEntry The ConstantPool MethodEntry we want. + * @param _isSpecial True if we wish to delegate to super (to support <code>super.foo()</code>) + * + * @return The Method or null if we fail to locate a given method. + */ + public ClassModelMethod getMethod(MethodEntry _methodEntry, boolean _isSpecial) { + final String entryClassNameInDotForm = _methodEntry.getClassEntry().getNameUTF8Entry().getUTF8().replace('/', '.'); + + // Shortcut direct calls to supers to allow "foo() { super.foo() }" type stuff to work + if (_isSpecial && (superClazz != null) && superClazz.isSuperClass(entryClassNameInDotForm)) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("going to look in super:" + superClazz.getClassWeAreModelling().getName() + " on behalf of " + + entryClassNameInDotForm); + } + return superClazz.getMethod(_methodEntry, false); + } + + NameAndTypeEntry nameAndTypeEntry = _methodEntry.getNameAndTypeEntry(); + ClassModelMethod methodOrNull = getMethodOrNull(nameAndTypeEntry.getNameUTF8Entry().getUTF8(), nameAndTypeEntry + .getDescriptorUTF8Entry().getUTF8()); + if (methodOrNull == null) + return superClazz != null ? superClazz.getMethod(_methodEntry, false) : (null); + return methodOrNull; + } + + // private ValueCache<MethodKey, MethodModel, AparapiException> methodModelCache = ValueCache.on(this::computeMethodModel); + private ValueCache<MethodKey, MethodModel, AparapiException> methodModelCache = ValueCache + .on(new ThrowingValueComputer<MethodKey, MethodModel, AparapiException>(){ + @Override public MethodModel compute(MethodKey key) throws AparapiException { + return computeMethodModel(key); + } + }); + + /** + * Create a MethodModel for a given method name and signature. + * + * @param _name + * @param _signature + * @return + * @throws AparapiException + */ + public MethodModel getMethodModel(String _name, String _signature) throws AparapiException { + if (CacheEnabler.areCachesEnabled()) + return methodModelCache.computeIfAbsent(MethodKey.of(_name, _signature)); + else { + final ClassModelMethod method = getMethod(_name, _signature); + return new MethodModel(method); + } + } + + private MethodModel computeMethodModel(MethodKey methodKey) throws AparapiException { + final ClassModelMethod method = getMethod(methodKey.getName(), methodKey.getSignature()); + return new MethodModel(method); + } + + // These fields use for accessor conversion + private final ArrayList<FieldEntry> structMembers = new ArrayList<FieldEntry>(); + + private final ArrayList<Long> structMemberOffsets = new ArrayList<Long>(); + + private final ArrayList<TypeSpec> structMemberTypes = new ArrayList<TypeSpec>(); + + private int totalStructSize = 0; + + public ArrayList<FieldEntry> getStructMembers() { + return structMembers; + } + + public ArrayList<Long> getStructMemberOffsets() { + return structMemberOffsets; + } + + public ArrayList<TypeSpec> getStructMemberTypes() { + return structMemberTypes; + } + + public int getTotalStructSize() { + return totalStructSize; + } + + public void setTotalStructSize(int x) { + totalStructSize = x; + } + + // private final ValueCache<EntrypointKey, Entrypoint, AparapiException> entrypointCache = ValueCache.on(this::computeBasicEntrypoint); + private final ValueCache<EntrypointKey, Entrypoint, AparapiException> entrypointCache = ValueCache + .on(new ThrowingValueComputer<EntrypointKey, Entrypoint, AparapiException>(){ + @Override public Entrypoint compute(EntrypointKey key) throws AparapiException { + return computeBasicEntrypoint(key); + } + }); + + Entrypoint getEntrypoint(String _entrypointName, String _descriptor, Object _k) throws AparapiException { + if (CacheEnabler.areCachesEnabled()) { + EntrypointKey key = EntrypointKey.of(_entrypointName, _descriptor); + long s = System.nanoTime(); + Entrypoint entrypointWithoutKernel = entrypointCache.computeIfAbsent(key); + long e = System.nanoTime() - s; + return entrypointWithoutKernel.cloneForKernel(_k); + } else { + final MethodModel method = getMethodModel(_entrypointName, _descriptor); + return new Entrypoint(this, method, _k); + } + } + + Entrypoint computeBasicEntrypoint(EntrypointKey entrypointKey) throws AparapiException { + final MethodModel method = getMethodModel(entrypointKey.getEntrypointName(), entrypointKey.getDescriptor()); + return new Entrypoint(this, method, null); + } + + public Class<?> getClassWeAreModelling() { + return clazz; + } + + public Entrypoint getEntrypoint(String _entrypointName, Object _k) throws AparapiException { + return (getEntrypoint(_entrypointName, "()V", _k)); + } + + public Entrypoint getEntrypoint() throws AparapiException { + return (getEntrypoint("run", "()V", null)); + } + + public static void invalidateCaches() { + classModelCache.invalidate(); + } + + @Override public String toString() { + return "ClassModel of " + getClassWeAreModelling(); + } +} diff --git a/src/main/java/com/aparapi/internal/model/Entrypoint.java b/src/main/java/com/aparapi/internal/model/Entrypoint.java index 287b406ded8812584a9d62b450bbe27bd7f2b969..c956816f0d5627eb54c56d7a69d01b2ab6269350 100644 --- a/src/main/java/com/aparapi/internal/model/Entrypoint.java +++ b/src/main/java/com/aparapi/internal/model/Entrypoint.java @@ -1,924 +1,924 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.model; - -import com.aparapi.*; -import com.aparapi.internal.exception.*; -import com.aparapi.internal.instruction.*; -import com.aparapi.internal.instruction.InstructionSet.*; -import com.aparapi.internal.model.ClassModel.*; -import com.aparapi.internal.model.ClassModel.ConstantPool.*; -import com.aparapi.internal.model.ClassModel.ConstantPool.MethodReferenceEntry.*; -import com.aparapi.internal.util.*; - -import java.lang.reflect.*; -import java.util.*; -import java.util.logging.*; - -public class Entrypoint implements Cloneable { - - private static Logger logger = Logger.getLogger(Config.getLoggerName()); - - private final List<ClassModel.ClassModelField> referencedClassModelFields = new ArrayList<ClassModel.ClassModelField>(); - - private final List<Field> referencedFields = new ArrayList<Field>(); - - private ClassModel classModel; - - private Object kernelInstance = null; - - private final Set<String> referencedFieldNames = new LinkedHashSet<String>(); - - private final Set<String> arrayFieldAssignments = new LinkedHashSet<String>(); - - private final Set<String> arrayFieldAccesses = new LinkedHashSet<String>(); - - // Classes of object array members - private final HashMap<String, ClassModel> objectArrayFieldsClasses = new HashMap<String, ClassModel>(); - - // Supporting classes of object array members like supers - private final HashMap<String, ClassModel> allFieldsClasses = new HashMap<String, ClassModel>(); - - // Keep track of arrays whose length is taken via foo.length - private final Set<String> arrayFieldArrayLengthUsed = new LinkedHashSet<String>(); - - private final List<MethodModel> calledMethods = new ArrayList<MethodModel>(); - - private final MethodModel methodModel; - - /** - True is an indication to use the fp64 pragma - */ - private boolean usesDoubles; - - /** - True is an indication to use the byte addressable store pragma - */ - private boolean usesByteWrites; - - /** - True is an indication to use the atomics pragmas - */ - private boolean usesAtomic32; - - private boolean usesAtomic64; - - public boolean requiresDoublePragma() { - return usesDoubles; - } - - public boolean requiresByteAddressableStorePragma() { - return usesByteWrites; - } - - /* Atomics are detected in Entrypoint */ - public void setRequiresAtomics32Pragma(boolean newVal) { - usesAtomic32 = newVal; - } - - public void setRequiresAtomics64Pragma(boolean newVal) { - usesAtomic64 = newVal; - } - - public boolean requiresAtomic32Pragma() { - return usesAtomic32; - } - - public boolean requiresAtomic64Pragma() { - return usesAtomic64; - } - - public Object getKernelInstance() { - return kernelInstance; - } - - public void setKernelInstance(Object _k) { - kernelInstance = _k; - } - - public Map<String, ClassModel> getObjectArrayFieldsClasses() { - return objectArrayFieldsClasses; - } - - public static Field getFieldFromClassHierarchy(Class<?> _clazz, String _name) throws AparapiException { - - // look in self - // if found, done - - // get superclass of curr class - // while not found - // get its fields - // if found - // if not private, done - // if private, failure - // if not found, get next superclass - - Field field = null; - - assert _name != null : "_name should not be null"; - - if (logger.isLoggable(Level.FINE)) { - logger.fine("looking for " + _name + " in " + _clazz.getName()); - } - - try { - field = _clazz.getDeclaredField(_name); - final Class<?> type = field.getType(); - if (type.isPrimitive() || type.isArray()) { - return field; - } - if (field.getAnnotation(Kernel.NoCL.class) != null) { - return null; - } - if (logger.isLoggable(Level.FINE)) { - logger.fine("field type is " + type.getName()); - } - throw new ClassParseException(ClassParseException.TYPE.OBJECTFIELDREFERENCE); - } catch (final NoSuchFieldException nsfe) { - // This should be looger fine... - //System.out.println("no " + _name + " in " + _clazz.getName()); - } - - Class<?> mySuper = _clazz.getSuperclass(); - - if (logger.isLoggable(Level.FINE)) { - logger.fine("looking for " + _name + " in " + mySuper.getName()); - } - - // Find better way to do this check - while (!mySuper.getName().equals(Kernel.class.getName())) { - try { - field = mySuper.getDeclaredField(_name); - final int modifiers = field.getModifiers(); - if ((Modifier.isStatic(modifiers) == false) && (Modifier.isPrivate(modifiers) == false)) { - final Class<?> type = field.getType(); - if (logger.isLoggable(Level.FINE)) { - logger.fine("field type is " + type.getName()); - } - if (type.isPrimitive() || type.isArray()) { - return field; - } - throw new ClassParseException(ClassParseException.TYPE.OBJECTFIELDREFERENCE); - } else { - // This should be looger fine... - //System.out.println("field " + _name + " not suitable: " + java.lang.reflect.Modifier.toString(modifiers)); - return null; - } - } catch (final NoSuchFieldException nsfe) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("no " + _name + " in " + mySuper.getName()); - } - mySuper = mySuper.getSuperclass(); - assert mySuper != null : "mySuper is null!"; - } - } - return null; - } - - /* - * Update the list of object array member classes and all the superclasses - * of those classes and the fields in each class - * - * It is important to have only one ClassModel for each class used in the kernel - * and only one MethodModel per method, so comparison operations work properly. - */ - public ClassModel getOrUpdateAllClassAccesses(String className) throws AparapiException { - ClassModel memberClassModel = allFieldsClasses.get(className); - if (memberClassModel == null) { - try { - final Class<?> memberClass = Class.forName(className); - - // Immediately add this class and all its supers if necessary - memberClassModel = ClassModel.createClassModel(memberClass); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("adding class " + className); - } - allFieldsClasses.put(className, memberClassModel); - ClassModel superModel = memberClassModel.getSuperClazz(); - while (superModel != null) { - // See if super is already added - final ClassModel oldSuper = allFieldsClasses.get(superModel.getClassWeAreModelling().getName()); - if (oldSuper != null) { - if (oldSuper != superModel) { - memberClassModel.replaceSuperClazz(oldSuper); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("replaced super " + oldSuper.getClassWeAreModelling().getName() + " for " + className); - } - } - } else { - allFieldsClasses.put(superModel.getClassWeAreModelling().getName(), superModel); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("add new super " + superModel.getClassWeAreModelling().getName() + " for " + className); - } - } - - superModel = superModel.getSuperClazz(); - } - } catch (final Exception e) { - if (logger.isLoggable(Level.INFO)) { - logger.info("Cannot find: " + className); - } - throw new AparapiException(e); - } - } - - return memberClassModel; - } - - public ClassModelMethod resolveAccessorCandidate(MethodCall _methodCall, MethodEntry _methodEntry) throws AparapiException { - final String methodsActualClassName = (_methodEntry.getClassEntry().getNameUTF8Entry().getUTF8()).replace('/', '.'); - - if (_methodCall instanceof VirtualMethodCall) { - final Instruction callInstance = ((VirtualMethodCall) _methodCall).getInstanceReference(); - if (callInstance instanceof AccessArrayElement) { - final AccessArrayElement arrayAccess = (AccessArrayElement) callInstance; - final Instruction refAccess = arrayAccess.getArrayRef(); - //if (refAccess instanceof I_GETFIELD) { - - // It is a call from a member obj array element - if (logger.isLoggable(Level.FINE)) { - logger.fine("Looking for class in accessor call: " + methodsActualClassName); - } - final ClassModel memberClassModel = getOrUpdateAllClassAccesses(methodsActualClassName); - - // false = no invokespecial allowed here - return memberClassModel.getMethod(_methodEntry, false); - //} - } - } - return null; - } - - /* - * Update accessor structures when there is a direct access to an - * obect array element's data members - */ - public void updateObjectMemberFieldAccesses(String className, FieldEntry field) throws AparapiException { - final String accessedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - - // Quickly bail if it is a ref - if (field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8().startsWith("L") - || field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8().startsWith("[L")) { - throw new ClassParseException(ClassParseException.TYPE.OBJECTARRAYFIELDREFERENCE); - } - - if (logger.isLoggable(Level.FINEST)) { - logger.finest("Updating access: " + className + " field:" + accessedFieldName); - } - - final ClassModel memberClassModel = getOrUpdateAllClassAccesses(className); - final Class<?> memberClass = memberClassModel.getClassWeAreModelling(); - ClassModel superCandidate = null; - - // We may add this field if no superclass match - boolean add = true; - - // No exact match, look for a superclass - for (final ClassModel c : allFieldsClasses.values()) { - if (logger.isLoggable(Level.FINEST)) { - logger.finest(" super: " + c.getClassWeAreModelling().getName() + " for " + className); - } - if (c.isSuperClass(memberClass)) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("selected super: " + c.getClassWeAreModelling().getName() + " for " + className); - } - superCandidate = c; - break; - } - - if (logger.isLoggable(Level.FINEST)) { - logger.finest(" no super match for " + memberClass.getName()); - } - } - - // Look at super's fields for a match - if (superCandidate != null) { - final ArrayList<FieldEntry> structMemberSet = superCandidate.getStructMembers(); - for (final FieldEntry f : structMemberSet) { - if (f.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(accessedFieldName) - && f.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8() - .equals(field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8())) { - - if (logger.isLoggable(Level.FINE)) { - logger.fine("Found match: " + accessedFieldName + " class: " + field.getClassEntry().getNameUTF8Entry().getUTF8() - + " to class: " + f.getClassEntry().getNameUTF8Entry().getUTF8()); - } - - if (!f.getClassEntry().getNameUTF8Entry().getUTF8().equals(field.getClassEntry().getNameUTF8Entry().getUTF8())) { - // Look up in class hierarchy to ensure it is the same field - final Field superField = getFieldFromClassHierarchy(superCandidate.getClassWeAreModelling(), f - .getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); - final Field classField = getFieldFromClassHierarchy(memberClass, f.getNameAndTypeEntry().getNameUTF8Entry() - .getUTF8()); - if (!superField.equals(classField)) { - throw new ClassParseException(ClassParseException.TYPE.OVERRIDENFIELD); - } - } - - add = false; - break; - } - } - } - - // There was no matching field in the supers, add it to the memberClassModel - // if not already there - if (add) { - boolean found = false; - final ArrayList<FieldEntry> structMemberSet = memberClassModel.getStructMembers(); - for (final FieldEntry f : structMemberSet) { - if (f.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(accessedFieldName) - && f.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8() - .equals(field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8())) { - found = true; - } - } - if (!found) { - structMemberSet.add(field); - if (logger.isLoggable(Level.FINE)) { - logger.fine("Adding assigned field " + field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8() + " type: " - + field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8() + " to " - + memberClassModel.getClassWeAreModelling().getName()); - } - } - } - } - - /* - * Find a suitable call target in the kernel class, supers, object members or static calls - */ - ClassModelMethod resolveCalledMethod(MethodCall methodCall, ClassModel classModel) throws AparapiException { - MethodEntry methodEntry = methodCall.getConstantPoolMethodEntry(); - int thisClassIndex = classModel.getThisClassConstantPoolIndex();//arf - boolean isMapped = (thisClassIndex != methodEntry.getClassIndex()) && Kernel.isMappedMethod(methodEntry); - if (logger.isLoggable(Level.FINE)) { - if (methodCall instanceof I_INVOKESPECIAL) { - logger.fine("Method call to super: " + methodEntry); - } else if (thisClassIndex != methodEntry.getClassIndex()) { - logger.fine("Method call to ??: " + methodEntry + ", isMappedMethod=" + isMapped); - } else { - logger.fine("Method call in kernel class: " + methodEntry); - } - } - - ClassModelMethod m = classModel.getMethod(methodEntry, (methodCall instanceof I_INVOKESPECIAL) ? true : false); - - // Did not find method in this class or supers. Look for data member object arrays - if (m == null && !isMapped) { - m = resolveAccessorCandidate(methodCall, methodEntry); - } - - // Look for a intra-object call in a object member - if (m == null && !isMapped) { - for (ClassModel c : allFieldsClasses.values()) { - if (c.getClassWeAreModelling().getName() - .equals(methodEntry.getClassEntry().getNameUTF8Entry().getUTF8().replace('/', '.'))) { - m = c.getMethod(methodEntry, (methodCall instanceof I_INVOKESPECIAL) ? true : false); - assert m != null; - break; - } - } - } - - // Look for static call to some other class - if ((m == null) && !isMapped && (methodCall instanceof I_INVOKESTATIC)) { - String otherClassName = methodEntry.getClassEntry().getNameUTF8Entry().getUTF8().replace('/', '.'); - ClassModel otherClassModel = getOrUpdateAllClassAccesses(otherClassName); - - //if (logger.isLoggable(Level.FINE)) { - // logger.fine("Looking for: " + methodEntry + " in other class " + otherClass.getName()); - //} - // false because INVOKESPECIAL not allowed here - m = otherClassModel.getMethod(methodEntry, false); - } - - if (logger.isLoggable(Level.INFO)) { - logger.fine("Selected method for: " + methodEntry + " is " + m); - } - - return m; - } - - public Entrypoint(ClassModel _classModel, MethodModel _methodModel, Object _k) throws AparapiException { - classModel = _classModel; - methodModel = _methodModel; - kernelInstance = _k; - - final Map<ClassModelMethod, MethodModel> methodMap = new LinkedHashMap<ClassModelMethod, MethodModel>(); - - boolean discovered = true; - - // Record which pragmas we need to enable - if (methodModel.requiresDoublePragma()) { - usesDoubles = true; - if (logger.isLoggable(Level.FINE)) { - logger.fine("Enabling doubles on " + methodModel.getName()); - } - - } - if (methodModel.requiresByteAddressableStorePragma()) { - usesByteWrites = true; - if (logger.isLoggable(Level.FINE)) { - logger.fine("Enabling byte addressable on " + methodModel.getName()); - } - } - - // Collect all methods called directly from kernel's run method - for (final MethodCall methodCall : methodModel.getMethodCalls()) { - - ClassModelMethod m = resolveCalledMethod(methodCall, classModel); - if ((m != null) && !methodMap.keySet().contains(m) && !noCL(m)) { - final MethodModel target = new MethodModel(m, this); - methodMap.put(m, target); - methodModel.getCalledMethods().add(target); - discovered = true; - } - } - - // methodMap now contains a list of method called by run itself(). - // Walk the whole graph of called methods and add them to the methodMap - while (discovered) { - discovered = false; - for (final MethodModel mm : new ArrayList<MethodModel>(methodMap.values())) { - for (final MethodCall methodCall : mm.getMethodCalls()) { - - ClassModelMethod m = resolveCalledMethod(methodCall, classModel); - if (m != null && !noCL(m)) { - MethodModel target = null; - if (methodMap.keySet().contains(m)) { - // we remove and then add again. Because this is a LinkedHashMap this - // places this at the end of the list underlying the map - // then when we reverse the collection (below) we get the method - // declarations in the correct order. We are trying to avoid creating forward references - target = methodMap.remove(m); - if (logger.isLoggable(Level.FINEST)) { - logger.fine("repositioning : " + m.getClassModel().getClassWeAreModelling().getName() + " " + m.getName() - + " " + m.getDescriptor()); - } - } else { - target = new MethodModel(m, this); - discovered = true; - } - methodMap.put(m, target); - // Build graph of call targets to look for recursion - mm.getCalledMethods().add(target); - } - } - } - } - - methodModel.checkForRecursion(new HashSet<MethodModel>()); - - calledMethods.addAll(methodMap.values()); - Collections.reverse(calledMethods); - final List<MethodModel> methods = new ArrayList<MethodModel>(calledMethods); - - // add method to the calledMethods so we can include in this list - methods.add(methodModel); - final Set<String> fieldAssignments = new HashSet<String>(); - - final Set<String> fieldAccesses = new HashSet<String>(); - - for (final MethodModel methodModel : methods) { - - // Record which pragmas we need to enable - if (methodModel.requiresDoublePragma()) { - usesDoubles = true; - if (logger.isLoggable(Level.FINE)) { - logger.fine("Enabling doubles on " + methodModel.getName()); - } - - } - if (methodModel.requiresByteAddressableStorePragma()) { - usesByteWrites = true; - if (logger.isLoggable(Level.FINE)) { - logger.fine("Enabling byte addressable on " + methodModel.getName()); - } - } - - for (Instruction instruction = methodModel.getPCHead(); instruction != null; instruction = instruction.getNextPC()) { - - if (instruction instanceof AssignToArrayElement) { - final AssignToArrayElement assignment = (AssignToArrayElement) instruction; - - final Instruction arrayRef = assignment.getArrayRef(); - // AccessField here allows instance and static array refs - if (arrayRef instanceof I_GETFIELD) { - final I_GETFIELD getField = (I_GETFIELD) arrayRef; - final FieldEntry field = getField.getConstantPoolFieldEntry(); - final String assignedArrayFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - arrayFieldAssignments.add(assignedArrayFieldName); - referencedFieldNames.add(assignedArrayFieldName); - - } - } else if (instruction instanceof AccessArrayElement) { - final AccessArrayElement access = (AccessArrayElement) instruction; - - final Instruction arrayRef = access.getArrayRef(); - // AccessField here allows instance and static array refs - if (arrayRef instanceof I_GETFIELD) { - final I_GETFIELD getField = (I_GETFIELD) arrayRef; - final FieldEntry field = getField.getConstantPoolFieldEntry(); - final String accessedArrayFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - arrayFieldAccesses.add(accessedArrayFieldName); - referencedFieldNames.add(accessedArrayFieldName); - - } - } else if (instruction instanceof I_ARRAYLENGTH) { - Instruction child = instruction.getFirstChild(); - while(child instanceof I_AALOAD) { - child = child.getFirstChild(); - } - if (!(child instanceof AccessField)) { - throw new ClassParseException(ClassParseException.TYPE.LOCALARRAYLENGTHACCESS); - } - final AccessField childField = (AccessField) child; - final String arrayName = childField.getConstantPoolFieldEntry().getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - arrayFieldArrayLengthUsed.add(arrayName); - if (logger.isLoggable(Level.FINE)) { - logger.fine("Noted arraylength in " + methodModel.getName() + " on " + arrayName); - } - } else if (instruction instanceof AccessField) { - final AccessField access = (AccessField) instruction; - final FieldEntry field = access.getConstantPoolFieldEntry(); - final String accessedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - fieldAccesses.add(accessedFieldName); - referencedFieldNames.add(accessedFieldName); - - final String signature = field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); - if (logger.isLoggable(Level.FINE)) { - logger.fine("AccessField field type= " + signature + " in " + methodModel.getName()); - } - - // Add the class model for the referenced obj array - if (signature.startsWith("[L")) { - // Turn [Lcom/aparapi/javalabs/opencl/demo/DummyOOA; into com.aparapi.javalabs.opencl.demo.DummyOOA for example - final String className = (signature.substring(2, signature.length() - 1)).replace('/', '.'); - final ClassModel arrayFieldModel = getOrUpdateAllClassAccesses(className); - if (arrayFieldModel != null) { - final Class<?> memberClass = arrayFieldModel.getClassWeAreModelling(); - final int modifiers = memberClass.getModifiers(); - if (!Modifier.isFinal(modifiers)) { - throw new ClassParseException(ClassParseException.TYPE.ACCESSEDOBJECTNONFINAL); - } - - final ClassModel refModel = objectArrayFieldsClasses.get(className); - if (refModel == null) { - - // Verify no other member with common parent - for (final ClassModel memberObjClass : objectArrayFieldsClasses.values()) { - ClassModel superModel = memberObjClass; - while (superModel != null) { - if (superModel.isSuperClass(memberClass)) { - throw new ClassParseException(ClassParseException.TYPE.ACCESSEDOBJECTFIELDNAMECONFLICT); - } - superModel = superModel.getSuperClazz(); - } - } - - objectArrayFieldsClasses.put(className, arrayFieldModel); - if (logger.isLoggable(Level.FINE)) { - logger.fine("adding class to objectArrayFields: " + className); - } - } - } - } else { - final String className = (field.getClassEntry().getNameUTF8Entry().getUTF8()).replace('/', '.'); - // Look for object data member access - if (!className.equals(getClassModel().getClassWeAreModelling().getName()) - && (getFieldFromClassHierarchy(getClassModel().getClassWeAreModelling(), accessedFieldName) == null)) { - updateObjectMemberFieldAccesses(className, field); - } - } - - } else if (instruction instanceof AssignToField) { - final AssignToField assignment = (AssignToField) instruction; - final FieldEntry field = assignment.getConstantPoolFieldEntry(); - final String assignedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - fieldAssignments.add(assignedFieldName); - referencedFieldNames.add(assignedFieldName); - - final String className = (field.getClassEntry().getNameUTF8Entry().getUTF8()).replace('/', '.'); - // Look for object data member access - if (!className.equals(getClassModel().getClassWeAreModelling().getName()) - && (getFieldFromClassHierarchy(getClassModel().getClassWeAreModelling(), assignedFieldName) == null)) { - updateObjectMemberFieldAccesses(className, field); - } else { - - if ((!Config.enablePUTFIELD) && methodModel.methodUsesPutfield() && !methodModel.isSetter()) { - throw new ClassParseException(ClassParseException.TYPE.ACCESSEDOBJECTONLYSUPPORTSSIMPLEPUTFIELD); - } - - } - - } - else if (instruction instanceof I_INVOKEVIRTUAL) { - final I_INVOKEVIRTUAL invokeInstruction = (I_INVOKEVIRTUAL) instruction; - MethodModel invokedMethod = invokeInstruction.getMethod(); - FieldEntry getterField = getSimpleGetterField(invokedMethod); - if (getterField != null) { - referencedFieldNames.add(getterField.getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); - } - else { - final MethodEntry methodEntry = invokeInstruction.getConstantPoolMethodEntry(); - if (Kernel.isMappedMethod(methodEntry)) { //only do this for intrinsics - - if (Kernel.usesAtomic32(methodEntry)) { - setRequiresAtomics32Pragma(true); - } - - final Arg methodArgs[] = methodEntry.getArgs(); - if ((methodArgs.length > 0) && methodArgs[0].isArray()) { //currently array arg can only take slot 0 - final Instruction arrInstruction = invokeInstruction.getArg(0); - if (arrInstruction instanceof AccessField) { - final AccessField access = (AccessField) arrInstruction; - final FieldEntry field = access.getConstantPoolFieldEntry(); - final String accessedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - arrayFieldAssignments.add(accessedFieldName); - referencedFieldNames.add(accessedFieldName); - } - else { - throw new ClassParseException(ClassParseException.TYPE.ACCESSEDOBJECTSETTERARRAY); - } - } - } - - } - } - } - } - - for (final String referencedFieldName : referencedFieldNames) { - - try { - final Class<?> clazz = classModel.getClassWeAreModelling(); - final Field field = getFieldFromClassHierarchy(clazz, referencedFieldName); - if (field != null) { - referencedFields.add(field); - final ClassModelField ff = classModel.getField(referencedFieldName); - assert ff != null : "ff should not be null for " + clazz.getName() + "." + referencedFieldName; - referencedClassModelFields.add(ff); - } - } catch (final SecurityException e) { - e.printStackTrace(); - } - } - - // Build data needed for oop form transforms if necessary - if (!objectArrayFieldsClasses.keySet().isEmpty()) { - - for (final ClassModel memberObjClass : objectArrayFieldsClasses.values()) { - - // At this point we have already done the field override safety check, so - // add all the superclass fields into the kernel member class to be - // sorted by size and emitted into the struct - ClassModel superModel = memberObjClass.getSuperClazz(); - while (superModel != null) { - if (logger.isLoggable(Level.FINEST)) { - logger.finest("adding = " + superModel.getClassWeAreModelling().getName() + " fields into " - + memberObjClass.getClassWeAreModelling().getName()); - } - memberObjClass.getStructMembers().addAll(superModel.getStructMembers()); - superModel = superModel.getSuperClazz(); - } - } - - // Sort fields of each class biggest->smallest - final Comparator<FieldEntry> fieldSizeComparator = new Comparator<FieldEntry>(){ - @Override public int compare(FieldEntry aa, FieldEntry bb) { - final String aType = aa.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); - final String bType = bb.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); - - // Booleans get converted down to bytes - final int aSize = InstructionSet.TypeSpec.valueOf(aType.equals("Z") ? "B" : aType).getSize(); - final int bSize = InstructionSet.TypeSpec.valueOf(bType.equals("Z") ? "B" : bType).getSize(); - - if (logger.isLoggable(Level.FINEST)) { - logger.finest("aType= " + aType + " aSize= " + aSize + " . . bType= " + bType + " bSize= " + bSize); - } - - // Note this is sorting in reverse order so the biggest is first - if (aSize > bSize) { - return -1; - } else if (aSize == bSize) { - return 0; - } else { - return 1; - } - } - }; - - for (final ClassModel c : objectArrayFieldsClasses.values()) { - final ArrayList<FieldEntry> fields = c.getStructMembers(); - if (fields.size() > 0) { - Collections.sort(fields, fieldSizeComparator); - - // Now compute the total size for the struct - int totalSize = 0; - int alignTo = 0; - - for (final FieldEntry f : fields) { - // Record field offset for use while copying - // Get field we will copy out of the kernel member object - final Field rfield = getFieldFromClassHierarchy(c.getClassWeAreModelling(), f.getNameAndTypeEntry() - .getNameUTF8Entry().getUTF8()); - - c.getStructMemberOffsets().add(UnsafeWrapper.objectFieldOffset(rfield)); - - final String fType = f.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); - //c.getStructMemberTypes().add(TypeSpec.valueOf(fType.equals("Z") ? "B" : fType)); - c.getStructMemberTypes().add(TypeSpec.valueOf(fType)); - final int fSize = TypeSpec.valueOf(fType.equals("Z") ? "B" : fType).getSize(); - if (fSize > alignTo) { - alignTo = fSize; - } - - totalSize += fSize; - if (logger.isLoggable(Level.FINEST)) { - logger.finest("Field = " + f.getNameAndTypeEntry().getNameUTF8Entry().getUTF8() + " size=" + fSize - + " totalSize=" + totalSize); - } - } - - // compute total size for OpenCL buffer - int totalStructSize = 0; - if ((totalSize % alignTo) == 0) { - totalStructSize = totalSize; - } else { - // Pad up if necessary - totalStructSize = ((totalSize / alignTo) + 1) * alignTo; - } - c.setTotalStructSize(totalStructSize); - } - } - } - } - - private boolean noCL(ClassModelMethod m) { - boolean found = m.getClassModel().getNoCLMethods().contains(m.getName()); - return found; - } - - private FieldEntry getSimpleGetterField(MethodModel method) { - return method.getAccessorVariableFieldEntry(); - } - - public List<ClassModel.ClassModelField> getReferencedClassModelFields() { - return (referencedClassModelFields); - } - - public List<Field> getReferencedFields() { - return (referencedFields); - } - - public List<MethodModel> getCalledMethods() { - return calledMethods; - } - - public Set<String> getReferencedFieldNames() { - return (referencedFieldNames); - } - - public Set<String> getArrayFieldAssignments() { - return (arrayFieldAssignments); - } - - public Set<String> getArrayFieldAccesses() { - return (arrayFieldAccesses); - } - - public Set<String> getArrayFieldArrayLengthUsed() { - return (arrayFieldArrayLengthUsed); - } - - public MethodModel getMethodModel() { - return (methodModel); - } - - public ClassModel getClassModel() { - return (classModel); - } - - /* - * Return the best call target MethodModel by looking in the class hierarchy - * @param _methodEntry MethodEntry for the desired target - * @return the fully qualified name such as "com_amd_javalabs_opencl_demo_PaternityTest$SimpleKernel__actuallyDoIt" - */ - public MethodModel getCallTarget(MethodEntry _methodEntry, boolean _isSpecial) { - ClassModelMethod target = getClassModel().getMethod(_methodEntry, _isSpecial); - boolean isMapped = Kernel.isMappedMethod(_methodEntry); - - if (logger.isLoggable(Level.FINE) && (target == null)) { - logger.fine("Did not find call target: " + _methodEntry + " in " + getClassModel().getClassWeAreModelling().getName() - + " isMapped=" + isMapped); - } - - if (target == null) { - // Look for member obj accessor calls - for (final ClassModel memberObjClass : objectArrayFieldsClasses.values()) { - final String entryClassNameInDotForm = _methodEntry.getClassEntry().getNameUTF8Entry().getUTF8().replace('/', '.'); - if (entryClassNameInDotForm.equals(memberObjClass.getClassWeAreModelling().getName())) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Searching for call target: " + _methodEntry + " in " - + memberObjClass.getClassWeAreModelling().getName()); - } - - target = memberObjClass.getMethod(_methodEntry, false); - if (target != null) { - break; - } - } - } - } - - if (target != null) { - for (final MethodModel m : calledMethods) { - if (m.getMethod() == target) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("selected from called methods = " + m.getName()); - } - return m; - } - } - } - - // Search for static calls to other classes - for (MethodModel m : calledMethods) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Searching for call target: " + _methodEntry + " in " + m.getName()); - } - if (m.getMethod().getName().equals(_methodEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8()) - && m.getMethod().getDescriptor().equals(_methodEntry.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8())) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Found " + m.getMethod().getClassModel().getClassWeAreModelling().getName() + "." - + m.getMethod().getName() + " " + m.getMethod().getDescriptor()); - } - return m; - } - } - - assert target == null : "Should not have missed a method in calledMethods"; - - return null; - } - - Entrypoint cloneForKernel(Object _k) throws AparapiException { - try { - Entrypoint clonedEntrypoint = (Entrypoint) clone(); - clonedEntrypoint.kernelInstance = _k; - return clonedEntrypoint; - } catch (CloneNotSupportedException e) { - throw new AparapiException(e); - } - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.model; + +import com.aparapi.*; +import com.aparapi.internal.exception.*; +import com.aparapi.internal.instruction.*; +import com.aparapi.internal.instruction.InstructionSet.*; +import com.aparapi.internal.model.ClassModel.*; +import com.aparapi.internal.model.ClassModel.ConstantPool.*; +import com.aparapi.internal.model.ClassModel.ConstantPool.MethodReferenceEntry.*; +import com.aparapi.internal.util.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.logging.*; + +public class Entrypoint implements Cloneable { + + private static Logger logger = Logger.getLogger(Config.getLoggerName()); + + private final List<ClassModel.ClassModelField> referencedClassModelFields = new ArrayList<ClassModel.ClassModelField>(); + + private final List<Field> referencedFields = new ArrayList<Field>(); + + private ClassModel classModel; + + private Object kernelInstance = null; + + private final Set<String> referencedFieldNames = new LinkedHashSet<String>(); + + private final Set<String> arrayFieldAssignments = new LinkedHashSet<String>(); + + private final Set<String> arrayFieldAccesses = new LinkedHashSet<String>(); + + // Classes of object array members + private final HashMap<String, ClassModel> objectArrayFieldsClasses = new HashMap<String, ClassModel>(); + + // Supporting classes of object array members like supers + private final HashMap<String, ClassModel> allFieldsClasses = new HashMap<String, ClassModel>(); + + // Keep track of arrays whose length is taken via foo.length + private final Set<String> arrayFieldArrayLengthUsed = new LinkedHashSet<String>(); + + private final List<MethodModel> calledMethods = new ArrayList<MethodModel>(); + + private final MethodModel methodModel; + + /** + True is an indication to use the fp64 pragma + */ + private boolean usesDoubles; + + /** + True is an indication to use the byte addressable store pragma + */ + private boolean usesByteWrites; + + /** + True is an indication to use the atomics pragmas + */ + private boolean usesAtomic32; + + private boolean usesAtomic64; + + public boolean requiresDoublePragma() { + return usesDoubles; + } + + public boolean requiresByteAddressableStorePragma() { + return usesByteWrites; + } + + /* Atomics are detected in Entrypoint */ + public void setRequiresAtomics32Pragma(boolean newVal) { + usesAtomic32 = newVal; + } + + public void setRequiresAtomics64Pragma(boolean newVal) { + usesAtomic64 = newVal; + } + + public boolean requiresAtomic32Pragma() { + return usesAtomic32; + } + + public boolean requiresAtomic64Pragma() { + return usesAtomic64; + } + + public Object getKernelInstance() { + return kernelInstance; + } + + public void setKernelInstance(Object _k) { + kernelInstance = _k; + } + + public Map<String, ClassModel> getObjectArrayFieldsClasses() { + return objectArrayFieldsClasses; + } + + public static Field getFieldFromClassHierarchy(Class<?> _clazz, String _name) throws AparapiException { + + // look in self + // if found, done + + // get superclass of curr class + // while not found + // get its fields + // if found + // if not private, done + // if private, failure + // if not found, get next superclass + + Field field = null; + + assert _name != null : "_name should not be null"; + + if (logger.isLoggable(Level.FINE)) { + logger.fine("looking for " + _name + " in " + _clazz.getName()); + } + + try { + field = _clazz.getDeclaredField(_name); + final Class<?> type = field.getType(); + if (type.isPrimitive() || type.isArray()) { + return field; + } + if (field.getAnnotation(Kernel.NoCL.class) != null) { + return null; + } + if (logger.isLoggable(Level.FINE)) { + logger.fine("field type is " + type.getName()); + } + throw new ClassParseException(ClassParseException.TYPE.OBJECTFIELDREFERENCE); + } catch (final NoSuchFieldException nsfe) { + // This should be looger fine... + //System.out.println("no " + _name + " in " + _clazz.getName()); + } + + Class<?> mySuper = _clazz.getSuperclass(); + + if (logger.isLoggable(Level.FINE)) { + logger.fine("looking for " + _name + " in " + mySuper.getName()); + } + + // Find better way to do this check + while (!mySuper.getName().equals(Kernel.class.getName())) { + try { + field = mySuper.getDeclaredField(_name); + final int modifiers = field.getModifiers(); + if ((Modifier.isStatic(modifiers) == false) && (Modifier.isPrivate(modifiers) == false)) { + final Class<?> type = field.getType(); + if (logger.isLoggable(Level.FINE)) { + logger.fine("field type is " + type.getName()); + } + if (type.isPrimitive() || type.isArray()) { + return field; + } + throw new ClassParseException(ClassParseException.TYPE.OBJECTFIELDREFERENCE); + } else { + // This should be looger fine... + //System.out.println("field " + _name + " not suitable: " + java.lang.reflect.Modifier.toString(modifiers)); + return null; + } + } catch (final NoSuchFieldException nsfe) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("no " + _name + " in " + mySuper.getName()); + } + mySuper = mySuper.getSuperclass(); + assert mySuper != null : "mySuper is null!"; + } + } + return null; + } + + /* + * Update the list of object array member classes and all the superclasses + * of those classes and the fields in each class + * + * It is important to have only one ClassModel for each class used in the kernel + * and only one MethodModel per method, so comparison operations work properly. + */ + public ClassModel getOrUpdateAllClassAccesses(String className) throws AparapiException { + ClassModel memberClassModel = allFieldsClasses.get(className); + if (memberClassModel == null) { + try { + final Class<?> memberClass = Class.forName(className); + + // Immediately add this class and all its supers if necessary + memberClassModel = ClassModel.createClassModel(memberClass); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("adding class " + className); + } + allFieldsClasses.put(className, memberClassModel); + ClassModel superModel = memberClassModel.getSuperClazz(); + while (superModel != null) { + // See if super is already added + final ClassModel oldSuper = allFieldsClasses.get(superModel.getClassWeAreModelling().getName()); + if (oldSuper != null) { + if (oldSuper != superModel) { + memberClassModel.replaceSuperClazz(oldSuper); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("replaced super " + oldSuper.getClassWeAreModelling().getName() + " for " + className); + } + } + } else { + allFieldsClasses.put(superModel.getClassWeAreModelling().getName(), superModel); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("add new super " + superModel.getClassWeAreModelling().getName() + " for " + className); + } + } + + superModel = superModel.getSuperClazz(); + } + } catch (final Exception e) { + if (logger.isLoggable(Level.INFO)) { + logger.info("Cannot find: " + className); + } + throw new AparapiException(e); + } + } + + return memberClassModel; + } + + public ClassModelMethod resolveAccessorCandidate(MethodCall _methodCall, MethodEntry _methodEntry) throws AparapiException { + final String methodsActualClassName = (_methodEntry.getClassEntry().getNameUTF8Entry().getUTF8()).replace('/', '.'); + + if (_methodCall instanceof VirtualMethodCall) { + final Instruction callInstance = ((VirtualMethodCall) _methodCall).getInstanceReference(); + if (callInstance instanceof AccessArrayElement) { + final AccessArrayElement arrayAccess = (AccessArrayElement) callInstance; + final Instruction refAccess = arrayAccess.getArrayRef(); + //if (refAccess instanceof I_GETFIELD) { + + // It is a call from a member obj array element + if (logger.isLoggable(Level.FINE)) { + logger.fine("Looking for class in accessor call: " + methodsActualClassName); + } + final ClassModel memberClassModel = getOrUpdateAllClassAccesses(methodsActualClassName); + + // false = no invokespecial allowed here + return memberClassModel.getMethod(_methodEntry, false); + //} + } + } + return null; + } + + /* + * Update accessor structures when there is a direct access to an + * obect array element's data members + */ + public void updateObjectMemberFieldAccesses(String className, FieldEntry field) throws AparapiException { + final String accessedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + + // Quickly bail if it is a ref + if (field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8().startsWith("L") + || field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8().startsWith("[L")) { + throw new ClassParseException(ClassParseException.TYPE.OBJECTARRAYFIELDREFERENCE); + } + + if (logger.isLoggable(Level.FINEST)) { + logger.finest("Updating access: " + className + " field:" + accessedFieldName); + } + + final ClassModel memberClassModel = getOrUpdateAllClassAccesses(className); + final Class<?> memberClass = memberClassModel.getClassWeAreModelling(); + ClassModel superCandidate = null; + + // We may add this field if no superclass match + boolean add = true; + + // No exact match, look for a superclass + for (final ClassModel c : allFieldsClasses.values()) { + if (logger.isLoggable(Level.FINEST)) { + logger.finest(" super: " + c.getClassWeAreModelling().getName() + " for " + className); + } + if (c.isSuperClass(memberClass)) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("selected super: " + c.getClassWeAreModelling().getName() + " for " + className); + } + superCandidate = c; + break; + } + + if (logger.isLoggable(Level.FINEST)) { + logger.finest(" no super match for " + memberClass.getName()); + } + } + + // Look at super's fields for a match + if (superCandidate != null) { + final ArrayList<FieldEntry> structMemberSet = superCandidate.getStructMembers(); + for (final FieldEntry f : structMemberSet) { + if (f.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(accessedFieldName) + && f.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8() + .equals(field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8())) { + + if (logger.isLoggable(Level.FINE)) { + logger.fine("Found match: " + accessedFieldName + " class: " + field.getClassEntry().getNameUTF8Entry().getUTF8() + + " to class: " + f.getClassEntry().getNameUTF8Entry().getUTF8()); + } + + if (!f.getClassEntry().getNameUTF8Entry().getUTF8().equals(field.getClassEntry().getNameUTF8Entry().getUTF8())) { + // Look up in class hierarchy to ensure it is the same field + final Field superField = getFieldFromClassHierarchy(superCandidate.getClassWeAreModelling(), f + .getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); + final Field classField = getFieldFromClassHierarchy(memberClass, f.getNameAndTypeEntry().getNameUTF8Entry() + .getUTF8()); + if (!superField.equals(classField)) { + throw new ClassParseException(ClassParseException.TYPE.OVERRIDENFIELD); + } + } + + add = false; + break; + } + } + } + + // There was no matching field in the supers, add it to the memberClassModel + // if not already there + if (add) { + boolean found = false; + final ArrayList<FieldEntry> structMemberSet = memberClassModel.getStructMembers(); + for (final FieldEntry f : structMemberSet) { + if (f.getNameAndTypeEntry().getNameUTF8Entry().getUTF8().equals(accessedFieldName) + && f.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8() + .equals(field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8())) { + found = true; + } + } + if (!found) { + structMemberSet.add(field); + if (logger.isLoggable(Level.FINE)) { + logger.fine("Adding assigned field " + field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8() + " type: " + + field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8() + " to " + + memberClassModel.getClassWeAreModelling().getName()); + } + } + } + } + + /* + * Find a suitable call target in the kernel class, supers, object members or static calls + */ + ClassModelMethod resolveCalledMethod(MethodCall methodCall, ClassModel classModel) throws AparapiException { + MethodEntry methodEntry = methodCall.getConstantPoolMethodEntry(); + int thisClassIndex = classModel.getThisClassConstantPoolIndex();//arf + boolean isMapped = (thisClassIndex != methodEntry.getClassIndex()) && Kernel.isMappedMethod(methodEntry); + if (logger.isLoggable(Level.FINE)) { + if (methodCall instanceof I_INVOKESPECIAL) { + logger.fine("Method call to super: " + methodEntry); + } else if (thisClassIndex != methodEntry.getClassIndex()) { + logger.fine("Method call to ??: " + methodEntry + ", isMappedMethod=" + isMapped); + } else { + logger.fine("Method call in kernel class: " + methodEntry); + } + } + + ClassModelMethod m = classModel.getMethod(methodEntry, (methodCall instanceof I_INVOKESPECIAL) ? true : false); + + // Did not find method in this class or supers. Look for data member object arrays + if (m == null && !isMapped) { + m = resolveAccessorCandidate(methodCall, methodEntry); + } + + // Look for a intra-object call in a object member + if (m == null && !isMapped) { + for (ClassModel c : allFieldsClasses.values()) { + if (c.getClassWeAreModelling().getName() + .equals(methodEntry.getClassEntry().getNameUTF8Entry().getUTF8().replace('/', '.'))) { + m = c.getMethod(methodEntry, (methodCall instanceof I_INVOKESPECIAL) ? true : false); + assert m != null; + break; + } + } + } + + // Look for static call to some other class + if ((m == null) && !isMapped && (methodCall instanceof I_INVOKESTATIC)) { + String otherClassName = methodEntry.getClassEntry().getNameUTF8Entry().getUTF8().replace('/', '.'); + ClassModel otherClassModel = getOrUpdateAllClassAccesses(otherClassName); + + //if (logger.isLoggable(Level.FINE)) { + // logger.fine("Looking for: " + methodEntry + " in other class " + otherClass.getName()); + //} + // false because INVOKESPECIAL not allowed here + m = otherClassModel.getMethod(methodEntry, false); + } + + if (logger.isLoggable(Level.INFO)) { + logger.fine("Selected method for: " + methodEntry + " is " + m); + } + + return m; + } + + public Entrypoint(ClassModel _classModel, MethodModel _methodModel, Object _k) throws AparapiException { + classModel = _classModel; + methodModel = _methodModel; + kernelInstance = _k; + + final Map<ClassModelMethod, MethodModel> methodMap = new LinkedHashMap<ClassModelMethod, MethodModel>(); + + boolean discovered = true; + + // Record which pragmas we need to enable + if (methodModel.requiresDoublePragma()) { + usesDoubles = true; + if (logger.isLoggable(Level.FINE)) { + logger.fine("Enabling doubles on " + methodModel.getName()); + } + + } + if (methodModel.requiresByteAddressableStorePragma()) { + usesByteWrites = true; + if (logger.isLoggable(Level.FINE)) { + logger.fine("Enabling byte addressable on " + methodModel.getName()); + } + } + + // Collect all methods called directly from kernel's run method + for (final MethodCall methodCall : methodModel.getMethodCalls()) { + + ClassModelMethod m = resolveCalledMethod(methodCall, classModel); + if ((m != null) && !methodMap.keySet().contains(m) && !noCL(m)) { + final MethodModel target = new MethodModel(m, this); + methodMap.put(m, target); + methodModel.getCalledMethods().add(target); + discovered = true; + } + } + + // methodMap now contains a list of method called by run itself(). + // Walk the whole graph of called methods and add them to the methodMap + while (discovered) { + discovered = false; + for (final MethodModel mm : new ArrayList<MethodModel>(methodMap.values())) { + for (final MethodCall methodCall : mm.getMethodCalls()) { + + ClassModelMethod m = resolveCalledMethod(methodCall, classModel); + if (m != null && !noCL(m)) { + MethodModel target = null; + if (methodMap.keySet().contains(m)) { + // we remove and then add again. Because this is a LinkedHashMap this + // places this at the end of the list underlying the map + // then when we reverse the collection (below) we get the method + // declarations in the correct order. We are trying to avoid creating forward references + target = methodMap.remove(m); + if (logger.isLoggable(Level.FINEST)) { + logger.fine("repositioning : " + m.getClassModel().getClassWeAreModelling().getName() + " " + m.getName() + + " " + m.getDescriptor()); + } + } else { + target = new MethodModel(m, this); + discovered = true; + } + methodMap.put(m, target); + // Build graph of call targets to look for recursion + mm.getCalledMethods().add(target); + } + } + } + } + + methodModel.checkForRecursion(new HashSet<MethodModel>()); + + calledMethods.addAll(methodMap.values()); + Collections.reverse(calledMethods); + final List<MethodModel> methods = new ArrayList<MethodModel>(calledMethods); + + // add method to the calledMethods so we can include in this list + methods.add(methodModel); + final Set<String> fieldAssignments = new HashSet<String>(); + + final Set<String> fieldAccesses = new HashSet<String>(); + + for (final MethodModel methodModel : methods) { + + // Record which pragmas we need to enable + if (methodModel.requiresDoublePragma()) { + usesDoubles = true; + if (logger.isLoggable(Level.FINE)) { + logger.fine("Enabling doubles on " + methodModel.getName()); + } + + } + if (methodModel.requiresByteAddressableStorePragma()) { + usesByteWrites = true; + if (logger.isLoggable(Level.FINE)) { + logger.fine("Enabling byte addressable on " + methodModel.getName()); + } + } + + for (Instruction instruction = methodModel.getPCHead(); instruction != null; instruction = instruction.getNextPC()) { + + if (instruction instanceof AssignToArrayElement) { + final AssignToArrayElement assignment = (AssignToArrayElement) instruction; + + final Instruction arrayRef = assignment.getArrayRef(); + // AccessField here allows instance and static array refs + if (arrayRef instanceof I_GETFIELD) { + final I_GETFIELD getField = (I_GETFIELD) arrayRef; + final FieldEntry field = getField.getConstantPoolFieldEntry(); + final String assignedArrayFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + arrayFieldAssignments.add(assignedArrayFieldName); + referencedFieldNames.add(assignedArrayFieldName); + + } + } else if (instruction instanceof AccessArrayElement) { + final AccessArrayElement access = (AccessArrayElement) instruction; + + final Instruction arrayRef = access.getArrayRef(); + // AccessField here allows instance and static array refs + if (arrayRef instanceof I_GETFIELD) { + final I_GETFIELD getField = (I_GETFIELD) arrayRef; + final FieldEntry field = getField.getConstantPoolFieldEntry(); + final String accessedArrayFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + arrayFieldAccesses.add(accessedArrayFieldName); + referencedFieldNames.add(accessedArrayFieldName); + + } + } else if (instruction instanceof I_ARRAYLENGTH) { + Instruction child = instruction.getFirstChild(); + while(child instanceof I_AALOAD) { + child = child.getFirstChild(); + } + if (!(child instanceof AccessField)) { + throw new ClassParseException(ClassParseException.TYPE.LOCALARRAYLENGTHACCESS); + } + final AccessField childField = (AccessField) child; + final String arrayName = childField.getConstantPoolFieldEntry().getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + arrayFieldArrayLengthUsed.add(arrayName); + if (logger.isLoggable(Level.FINE)) { + logger.fine("Noted arraylength in " + methodModel.getName() + " on " + arrayName); + } + } else if (instruction instanceof AccessField) { + final AccessField access = (AccessField) instruction; + final FieldEntry field = access.getConstantPoolFieldEntry(); + final String accessedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + fieldAccesses.add(accessedFieldName); + referencedFieldNames.add(accessedFieldName); + + final String signature = field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); + if (logger.isLoggable(Level.FINE)) { + logger.fine("AccessField field type= " + signature + " in " + methodModel.getName()); + } + + // Add the class model for the referenced obj array + if (signature.startsWith("[L")) { + // Turn [Lcom/aparapi/javalabs/opencl/demo/DummyOOA; into com.aparapi.javalabs.opencl.demo.DummyOOA for example + final String className = (signature.substring(2, signature.length() - 1)).replace('/', '.'); + final ClassModel arrayFieldModel = getOrUpdateAllClassAccesses(className); + if (arrayFieldModel != null) { + final Class<?> memberClass = arrayFieldModel.getClassWeAreModelling(); + final int modifiers = memberClass.getModifiers(); + if (!Modifier.isFinal(modifiers)) { + throw new ClassParseException(ClassParseException.TYPE.ACCESSEDOBJECTNONFINAL); + } + + final ClassModel refModel = objectArrayFieldsClasses.get(className); + if (refModel == null) { + + // Verify no other member with common parent + for (final ClassModel memberObjClass : objectArrayFieldsClasses.values()) { + ClassModel superModel = memberObjClass; + while (superModel != null) { + if (superModel.isSuperClass(memberClass)) { + throw new ClassParseException(ClassParseException.TYPE.ACCESSEDOBJECTFIELDNAMECONFLICT); + } + superModel = superModel.getSuperClazz(); + } + } + + objectArrayFieldsClasses.put(className, arrayFieldModel); + if (logger.isLoggable(Level.FINE)) { + logger.fine("adding class to objectArrayFields: " + className); + } + } + } + } else { + final String className = (field.getClassEntry().getNameUTF8Entry().getUTF8()).replace('/', '.'); + // Look for object data member access + if (!className.equals(getClassModel().getClassWeAreModelling().getName()) + && (getFieldFromClassHierarchy(getClassModel().getClassWeAreModelling(), accessedFieldName) == null)) { + updateObjectMemberFieldAccesses(className, field); + } + } + + } else if (instruction instanceof AssignToField) { + final AssignToField assignment = (AssignToField) instruction; + final FieldEntry field = assignment.getConstantPoolFieldEntry(); + final String assignedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + fieldAssignments.add(assignedFieldName); + referencedFieldNames.add(assignedFieldName); + + final String className = (field.getClassEntry().getNameUTF8Entry().getUTF8()).replace('/', '.'); + // Look for object data member access + if (!className.equals(getClassModel().getClassWeAreModelling().getName()) + && (getFieldFromClassHierarchy(getClassModel().getClassWeAreModelling(), assignedFieldName) == null)) { + updateObjectMemberFieldAccesses(className, field); + } else { + + if ((!Config.enablePUTFIELD) && methodModel.methodUsesPutfield() && !methodModel.isSetter()) { + throw new ClassParseException(ClassParseException.TYPE.ACCESSEDOBJECTONLYSUPPORTSSIMPLEPUTFIELD); + } + + } + + } + else if (instruction instanceof I_INVOKEVIRTUAL) { + final I_INVOKEVIRTUAL invokeInstruction = (I_INVOKEVIRTUAL) instruction; + MethodModel invokedMethod = invokeInstruction.getMethod(); + FieldEntry getterField = getSimpleGetterField(invokedMethod); + if (getterField != null) { + referencedFieldNames.add(getterField.getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); + } + else { + final MethodEntry methodEntry = invokeInstruction.getConstantPoolMethodEntry(); + if (Kernel.isMappedMethod(methodEntry)) { //only do this for intrinsics + + if (Kernel.usesAtomic32(methodEntry)) { + setRequiresAtomics32Pragma(true); + } + + final Arg methodArgs[] = methodEntry.getArgs(); + if ((methodArgs.length > 0) && methodArgs[0].isArray()) { //currently array arg can only take slot 0 + final Instruction arrInstruction = invokeInstruction.getArg(0); + if (arrInstruction instanceof AccessField) { + final AccessField access = (AccessField) arrInstruction; + final FieldEntry field = access.getConstantPoolFieldEntry(); + final String accessedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + arrayFieldAssignments.add(accessedFieldName); + referencedFieldNames.add(accessedFieldName); + } + else { + throw new ClassParseException(ClassParseException.TYPE.ACCESSEDOBJECTSETTERARRAY); + } + } + } + + } + } + } + } + + for (final String referencedFieldName : referencedFieldNames) { + + try { + final Class<?> clazz = classModel.getClassWeAreModelling(); + final Field field = getFieldFromClassHierarchy(clazz, referencedFieldName); + if (field != null) { + referencedFields.add(field); + final ClassModelField ff = classModel.getField(referencedFieldName); + assert ff != null : "ff should not be null for " + clazz.getName() + "." + referencedFieldName; + referencedClassModelFields.add(ff); + } + } catch (final SecurityException e) { + e.printStackTrace(); + } + } + + // Build data needed for oop form transforms if necessary + if (!objectArrayFieldsClasses.keySet().isEmpty()) { + + for (final ClassModel memberObjClass : objectArrayFieldsClasses.values()) { + + // At this point we have already done the field override safety check, so + // add all the superclass fields into the kernel member class to be + // sorted by size and emitted into the struct + ClassModel superModel = memberObjClass.getSuperClazz(); + while (superModel != null) { + if (logger.isLoggable(Level.FINEST)) { + logger.finest("adding = " + superModel.getClassWeAreModelling().getName() + " fields into " + + memberObjClass.getClassWeAreModelling().getName()); + } + memberObjClass.getStructMembers().addAll(superModel.getStructMembers()); + superModel = superModel.getSuperClazz(); + } + } + + // Sort fields of each class biggest->smallest + final Comparator<FieldEntry> fieldSizeComparator = new Comparator<FieldEntry>(){ + @Override public int compare(FieldEntry aa, FieldEntry bb) { + final String aType = aa.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); + final String bType = bb.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); + + // Booleans get converted down to bytes + final int aSize = InstructionSet.TypeSpec.valueOf(aType.equals("Z") ? "B" : aType).getSize(); + final int bSize = InstructionSet.TypeSpec.valueOf(bType.equals("Z") ? "B" : bType).getSize(); + + if (logger.isLoggable(Level.FINEST)) { + logger.finest("aType= " + aType + " aSize= " + aSize + " . . bType= " + bType + " bSize= " + bSize); + } + + // Note this is sorting in reverse order so the biggest is first + if (aSize > bSize) { + return -1; + } else if (aSize == bSize) { + return 0; + } else { + return 1; + } + } + }; + + for (final ClassModel c : objectArrayFieldsClasses.values()) { + final ArrayList<FieldEntry> fields = c.getStructMembers(); + if (fields.size() > 0) { + Collections.sort(fields, fieldSizeComparator); + + // Now compute the total size for the struct + int totalSize = 0; + int alignTo = 0; + + for (final FieldEntry f : fields) { + // Record field offset for use while copying + // Get field we will copy out of the kernel member object + final Field rfield = getFieldFromClassHierarchy(c.getClassWeAreModelling(), f.getNameAndTypeEntry() + .getNameUTF8Entry().getUTF8()); + + c.getStructMemberOffsets().add(UnsafeWrapper.objectFieldOffset(rfield)); + + final String fType = f.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); + //c.getStructMemberTypes().add(TypeSpec.valueOf(fType.equals("Z") ? "B" : fType)); + c.getStructMemberTypes().add(TypeSpec.valueOf(fType)); + final int fSize = TypeSpec.valueOf(fType.equals("Z") ? "B" : fType).getSize(); + if (fSize > alignTo) { + alignTo = fSize; + } + + totalSize += fSize; + if (logger.isLoggable(Level.FINEST)) { + logger.finest("Field = " + f.getNameAndTypeEntry().getNameUTF8Entry().getUTF8() + " size=" + fSize + + " totalSize=" + totalSize); + } + } + + // compute total size for OpenCL buffer + int totalStructSize = 0; + if ((totalSize % alignTo) == 0) { + totalStructSize = totalSize; + } else { + // Pad up if necessary + totalStructSize = ((totalSize / alignTo) + 1) * alignTo; + } + c.setTotalStructSize(totalStructSize); + } + } + } + } + + private boolean noCL(ClassModelMethod m) { + boolean found = m.getClassModel().getNoCLMethods().contains(m.getName()); + return found; + } + + private FieldEntry getSimpleGetterField(MethodModel method) { + return method.getAccessorVariableFieldEntry(); + } + + public List<ClassModel.ClassModelField> getReferencedClassModelFields() { + return (referencedClassModelFields); + } + + public List<Field> getReferencedFields() { + return (referencedFields); + } + + public List<MethodModel> getCalledMethods() { + return calledMethods; + } + + public Set<String> getReferencedFieldNames() { + return (referencedFieldNames); + } + + public Set<String> getArrayFieldAssignments() { + return (arrayFieldAssignments); + } + + public Set<String> getArrayFieldAccesses() { + return (arrayFieldAccesses); + } + + public Set<String> getArrayFieldArrayLengthUsed() { + return (arrayFieldArrayLengthUsed); + } + + public MethodModel getMethodModel() { + return (methodModel); + } + + public ClassModel getClassModel() { + return (classModel); + } + + /* + * Return the best call target MethodModel by looking in the class hierarchy + * @param _methodEntry MethodEntry for the desired target + * @return the fully qualified name such as "com_amd_javalabs_opencl_demo_PaternityTest$SimpleKernel__actuallyDoIt" + */ + public MethodModel getCallTarget(MethodEntry _methodEntry, boolean _isSpecial) { + ClassModelMethod target = getClassModel().getMethod(_methodEntry, _isSpecial); + boolean isMapped = Kernel.isMappedMethod(_methodEntry); + + if (logger.isLoggable(Level.FINE) && (target == null)) { + logger.fine("Did not find call target: " + _methodEntry + " in " + getClassModel().getClassWeAreModelling().getName() + + " isMapped=" + isMapped); + } + + if (target == null) { + // Look for member obj accessor calls + for (final ClassModel memberObjClass : objectArrayFieldsClasses.values()) { + final String entryClassNameInDotForm = _methodEntry.getClassEntry().getNameUTF8Entry().getUTF8().replace('/', '.'); + if (entryClassNameInDotForm.equals(memberObjClass.getClassWeAreModelling().getName())) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Searching for call target: " + _methodEntry + " in " + + memberObjClass.getClassWeAreModelling().getName()); + } + + target = memberObjClass.getMethod(_methodEntry, false); + if (target != null) { + break; + } + } + } + } + + if (target != null) { + for (final MethodModel m : calledMethods) { + if (m.getMethod() == target) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("selected from called methods = " + m.getName()); + } + return m; + } + } + } + + // Search for static calls to other classes + for (MethodModel m : calledMethods) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Searching for call target: " + _methodEntry + " in " + m.getName()); + } + if (m.getMethod().getName().equals(_methodEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8()) + && m.getMethod().getDescriptor().equals(_methodEntry.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8())) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Found " + m.getMethod().getClassModel().getClassWeAreModelling().getName() + "." + + m.getMethod().getName() + " " + m.getMethod().getDescriptor()); + } + return m; + } + } + + assert target == null : "Should not have missed a method in calledMethods"; + + return null; + } + + Entrypoint cloneForKernel(Object _k) throws AparapiException { + try { + Entrypoint clonedEntrypoint = (Entrypoint) clone(); + clonedEntrypoint.kernelInstance = _k; + return clonedEntrypoint; + } catch (CloneNotSupportedException e) { + throw new AparapiException(e); + } + } +} diff --git a/src/main/java/com/aparapi/internal/model/EntrypointKey.java b/src/main/java/com/aparapi/internal/model/EntrypointKey.java index 3280f44ea7579e50e6187f3a7655c80f59d6d969..fe5530bc5dfdc04bcec09625baabf5a5fc028e06 100644 --- a/src/main/java/com/aparapi/internal/model/EntrypointKey.java +++ b/src/main/java/com/aparapi/internal/model/EntrypointKey.java @@ -1,72 +1,72 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.model; - -final class EntrypointKey{ - public static EntrypointKey of(String entrypointName, String descriptor) { - return new EntrypointKey(entrypointName, descriptor); - } - - private String descriptor; - - private String entrypointName; - - private EntrypointKey(String entrypointName, String descriptor) { - this.entrypointName = entrypointName; - this.descriptor = descriptor; - } - - String getDescriptor() { - return descriptor; - } - - String getEntrypointName() { - return entrypointName; - } - - @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((descriptor == null) ? 0 : descriptor.hashCode()); - result = prime * result + ((entrypointName == null) ? 0 : entrypointName.hashCode()); - return result; - } - - @Override public String toString() { - return "EntrypointKey [entrypointName=" + entrypointName + ", descriptor=" + descriptor + "]"; - } - - @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - EntrypointKey other = (EntrypointKey) obj; - if (descriptor == null) { - if (other.descriptor != null) - return false; - } else if (!descriptor.equals(other.descriptor)) - return false; - if (entrypointName == null) { - if (other.entrypointName != null) - return false; - } else if (!entrypointName.equals(other.entrypointName)) - return false; - return true; - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.model; + +final class EntrypointKey{ + public static EntrypointKey of(String entrypointName, String descriptor) { + return new EntrypointKey(entrypointName, descriptor); + } + + private String descriptor; + + private String entrypointName; + + private EntrypointKey(String entrypointName, String descriptor) { + this.entrypointName = entrypointName; + this.descriptor = descriptor; + } + + String getDescriptor() { + return descriptor; + } + + String getEntrypointName() { + return entrypointName; + } + + @Override public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((descriptor == null) ? 0 : descriptor.hashCode()); + result = prime * result + ((entrypointName == null) ? 0 : entrypointName.hashCode()); + return result; + } + + @Override public String toString() { + return "EntrypointKey [entrypointName=" + entrypointName + ", descriptor=" + descriptor + "]"; + } + + @Override public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + EntrypointKey other = (EntrypointKey) obj; + if (descriptor == null) { + if (other.descriptor != null) + return false; + } else if (!descriptor.equals(other.descriptor)) + return false; + if (entrypointName == null) { + if (other.entrypointName != null) + return false; + } else if (!entrypointName.equals(other.entrypointName)) + return false; + return true; + } +} diff --git a/src/main/java/com/aparapi/internal/model/Memoizer.java b/src/main/java/com/aparapi/internal/model/Memoizer.java index b72be234f20a855402a713f03036003876ea0cf6..60c8d1524e6c443c41190f86e2d31860b245a96b 100644 --- a/src/main/java/com/aparapi/internal/model/Memoizer.java +++ b/src/main/java/com/aparapi/internal/model/Memoizer.java @@ -1,99 +1,99 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.model; - -import java.util.*; -import java.util.concurrent.atomic.*; - -interface Optional<E> { - final class Some<E> implements Optional<E>{ - private final E value; - - static final <E> Optional<E> of(E value) { - return new Some<>(value); - } - - private Some(E value) { - this.value = value; - } - - @Override public E get() { - return value; - } - - @Override public boolean isPresent() { - return true; - } - } - - final class None<E> implements Optional<E>{ - @SuppressWarnings("unchecked") static <E> Optional<E> none() { - return none; - } - - @SuppressWarnings("rawtypes") private static final None none = new None(); - - private None() { - // Do nothing - } - - @Override public E get() { - throw new NoSuchElementException("No value present"); - } - - @Override public boolean isPresent() { - return false; - } - } - - E get(); - - boolean isPresent(); -} - -public interface Memoizer<T> extends Supplier<T> { - public final class Impl<T> implements Memoizer<T>{ - private final Supplier<T> supplier; - - private final AtomicReference<Optional<T>> valueRef = new AtomicReference<>(Optional.None.<T> none()); - - Impl(Supplier<T> supplier) { - this.supplier = supplier; - } - - @Override public T get() { - Optional<T> value = valueRef.get(); - while (!value.isPresent()) { - Optional<T> newValue = Optional.Some.of(supplier.get()); - if (valueRef.compareAndSet(value, newValue)) { - value = newValue; - break; - } - value = valueRef.get(); - } - return value.get(); - } - - public static <T> Memoizer<T> of(Supplier<T> supplier) { - return new Impl<>(supplier); - } - } - - // static <T> Memoizer<T> of(Supplier<T> supplier) - // { - // return new Impl<>(supplier); - // } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.model; + +import java.util.*; +import java.util.concurrent.atomic.*; + +interface Optional<E> { + final class Some<E> implements Optional<E>{ + private final E value; + + static final <E> Optional<E> of(E value) { + return new Some<>(value); + } + + private Some(E value) { + this.value = value; + } + + @Override public E get() { + return value; + } + + @Override public boolean isPresent() { + return true; + } + } + + final class None<E> implements Optional<E>{ + @SuppressWarnings("unchecked") static <E> Optional<E> none() { + return none; + } + + @SuppressWarnings("rawtypes") private static final None none = new None(); + + private None() { + // Do nothing + } + + @Override public E get() { + throw new NoSuchElementException("No value present"); + } + + @Override public boolean isPresent() { + return false; + } + } + + E get(); + + boolean isPresent(); +} + +public interface Memoizer<T> extends Supplier<T> { + public final class Impl<T> implements Memoizer<T>{ + private final Supplier<T> supplier; + + private final AtomicReference<Optional<T>> valueRef = new AtomicReference<>(Optional.None.<T> none()); + + Impl(Supplier<T> supplier) { + this.supplier = supplier; + } + + @Override public T get() { + Optional<T> value = valueRef.get(); + while (!value.isPresent()) { + Optional<T> newValue = Optional.Some.of(supplier.get()); + if (valueRef.compareAndSet(value, newValue)) { + value = newValue; + break; + } + value = valueRef.get(); + } + return value.get(); + } + + public static <T> Memoizer<T> of(Supplier<T> supplier) { + return new Impl<>(supplier); + } + } + + // static <T> Memoizer<T> of(Supplier<T> supplier) + // { + // return new Impl<>(supplier); + // } +} diff --git a/src/main/java/com/aparapi/internal/model/MethodKey.java b/src/main/java/com/aparapi/internal/model/MethodKey.java index b6afea1fccbb2cbbffff1478626ca593ebbf7426..28f5921d8c4d401a4601672e0ec426982a7aad51 100644 --- a/src/main/java/com/aparapi/internal/model/MethodKey.java +++ b/src/main/java/com/aparapi/internal/model/MethodKey.java @@ -1,72 +1,72 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.model; - -final class MethodKey{ - static MethodKey of(String name, String signature) { - return new MethodKey(name, signature); - } - - private final String name; - - private final String signature; - - @Override public String toString() { - return "MethodKey [name=" + getName() + ", signature=" + getSignature() + "]"; - } - - @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((getName() == null) ? 0 : getName().hashCode()); - result = prime * result + ((getSignature() == null) ? 0 : getSignature().hashCode()); - return result; - } - - @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - MethodKey other = (MethodKey) obj; - if (getName() == null) { - if (other.getName() != null) - return false; - } else if (!getName().equals(other.getName())) - return false; - if (getSignature() == null) { - if (other.getSignature() != null) - return false; - } else if (!getSignature().equals(other.getSignature())) - return false; - return true; - } - - private MethodKey(String name, String signature) { - this.name = name; - this.signature = signature; - } - - public String getName() { - return name; - } - - public String getSignature() { - return signature; - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.model; + +final class MethodKey{ + static MethodKey of(String name, String signature) { + return new MethodKey(name, signature); + } + + private final String name; + + private final String signature; + + @Override public String toString() { + return "MethodKey [name=" + getName() + ", signature=" + getSignature() + "]"; + } + + @Override public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getName() == null) ? 0 : getName().hashCode()); + result = prime * result + ((getSignature() == null) ? 0 : getSignature().hashCode()); + return result; + } + + @Override public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MethodKey other = (MethodKey) obj; + if (getName() == null) { + if (other.getName() != null) + return false; + } else if (!getName().equals(other.getName())) + return false; + if (getSignature() == null) { + if (other.getSignature() != null) + return false; + } else if (!getSignature().equals(other.getSignature())) + return false; + return true; + } + + private MethodKey(String name, String signature) { + this.name = name; + this.signature = signature; + } + + public String getName() { + return name; + } + + public String getSignature() { + return signature; + } +} diff --git a/src/main/java/com/aparapi/internal/model/MethodModel.java b/src/main/java/com/aparapi/internal/model/MethodModel.java index d46e98a4e19b13b2c3f9f2b16fd85a5cdd3acd95..da7702f9b10591ef21ff958caad53e817ce96ca3 100644 --- a/src/main/java/com/aparapi/internal/model/MethodModel.java +++ b/src/main/java/com/aparapi/internal/model/MethodModel.java @@ -1,1748 +1,1748 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - - */ -package com.aparapi.internal.model; - -import com.aparapi.*; -import com.aparapi.internal.exception.*; -import com.aparapi.internal.instruction.*; -import com.aparapi.internal.instruction.InstructionPattern.*; -import com.aparapi.internal.instruction.InstructionSet.*; -import com.aparapi.internal.model.ClassModel.*; -import com.aparapi.internal.model.ClassModel.ConstantPool.*; -import com.aparapi.internal.model.ClassModel.ConstantPool.MethodReferenceEntry.*; -import com.aparapi.internal.reader.*; - -import java.util.*; -import java.util.Map.Entry; -import java.util.logging.*; - -public class MethodModel{ - - private static Logger logger = Logger.getLogger(Config.getLoggerName()); - - private ExpressionList expressionList; - - private ClassModelMethod method; - - /** - True is an indication to use the fp64 pragma - */ - private boolean usesDoubles; - - /** - True is an indication to use the byte addressable store pragma - */ - private boolean usesByteWrites; - - private boolean methodIsGetter; - - private boolean methodIsSetter; - - private boolean methodIsPrivateMemoryGetter = false; - - // Only setters can use putfield - private boolean usesPutfield; - - private FieldEntry accessorVariableFieldEntry; - - private boolean noCL = false; - - public boolean isGetter() { - return methodIsGetter; - } - - public boolean isSetter() { - return methodIsSetter; - } - - public boolean methodUsesPutfield() { - return usesPutfield; - } - - public boolean isNoCL() { - return noCL; - } - - public boolean isPrivateMemoryGetter() { - return methodIsPrivateMemoryGetter; - } - - public ClassModelMethod getMethod() { - return method; - } - - public FieldEntry getAccessorVariableFieldEntry() { - return accessorVariableFieldEntry; - } - - private final Set<MethodModel> calledMethods = new HashSet<MethodModel>(); - - public Set<MethodModel> getCalledMethods() { - return calledMethods; - } - - public void checkForRecursion(Set<MethodModel> transitiveCalledMethods) throws AparapiException { - - if (transitiveCalledMethods.contains(this)) { - throw new ClassParseException(ClassParseException.TYPE.RECURSION, getName()); - } - - // Add myself - transitiveCalledMethods.add(this); - - // For each callee, send him a copy of the call chain up to this method - final Iterator<MethodModel> cmi = getCalledMethods().iterator(); - while (cmi.hasNext()) { - final MethodModel next = cmi.next(); - next.checkForRecursion(transitiveCalledMethods); - } - - // Done examining this call path, remove myself - transitiveCalledMethods.remove(this); - } - - /** - * After we have folded the top level instructions this root list will contain a list of all of the 'root' instructions (stores/loops/conditionals) - * We are going to build a linked list. Here we track the head and tail - */ - private Instruction pcTail = null; - - private Instruction pcHead = null; - - /** - * Look at each instruction for use of long/double or byte writes which - * require pragmas to be used in the OpenCL source - * - */ - public void setRequiredPragmas(Instruction instruction) { - final boolean setDouble = instruction.getByteCode().usesDouble(); - if (setDouble) { - usesDoubles = true; - if (logger.isLoggable(Level.FINE)) { - logger.fine("Found D on =" + instruction + " in " + getName()); - } - } - - if ((instruction instanceof I_BASTORE) || (instruction instanceof I_CASTORE /* || instruction instanceof I_SASTORE */)) { - usesByteWrites = true; - if (usesByteWrites && logger.isLoggable(Level.FINE)) { - logger.fine("Found Byte Addressable Store on =" + instruction + " in " + getName()); - } - } - } - - public boolean requiresDoublePragma() { - return usesDoubles; - } - - public boolean requiresByteAddressableStorePragma() { - return usesByteWrites; - } - - /** - * Create a linked list of instructions (from pcHead to pcTail). - * - * Returns a map of int (pc) to Instruction which to allow us to quickly get from a bytecode offset to the appropriate instruction. - * - * Note that not all int values from 0 to code.length values will map to a valid instruction, if pcMap.get(n) == null then this implies - * that 'n' is not the start of an instruction - * - * So either pcMap.get(i)== null or pcMap.get(i).getThisPC()==i - * - * @return Map<Integer, Instruction> the returned pc to Instruction map - */ - public Map<Integer, Instruction> createListOfInstructions() throws ClassParseException { - final Map<Integer, Instruction> pcMap = new LinkedHashMap<Integer, Instruction>(); - final byte[] code = method.getCode(); - - // We create a byteReader for reading the bytes from the code array - final ByteReader codeReader = new ByteReader(code); - while (codeReader.hasMore()) { - // Create an instruction from code reader's current position - final int pc = codeReader.getOffset(); - final Instruction instruction = InstructionSet.ByteCode.create(this, codeReader); - - if ((!Config.enablePUTFIELD) && (instruction instanceof I_PUTFIELD)) { - // Special case putfield handling to allow object setter processing - // and bail later if necessary - //throw new ClassParseException("We don't support putfield instructions"); - usesPutfield = true; - } - - if ((!Config.enableARETURN) && (instruction instanceof I_ARETURN)) { - throw new ClassParseException(instruction, ClassParseException.TYPE.ARRAY_RETURN); - } - - if ((!Config.enablePUTSTATIC) && (instruction instanceof I_PUTSTATIC)) { - throw new ClassParseException(instruction, ClassParseException.TYPE.PUTFIELD); - } - - if ((!Config.enableINVOKEINTERFACE) && (instruction instanceof I_INVOKEINTERFACE)) { - throw new ClassParseException(instruction, ClassParseException.TYPE.INVOKEINTERFACE); - } - - if ((!Config.enableGETSTATIC) && (instruction instanceof I_GETSTATIC)) { - throw new ClassParseException(instruction, ClassParseException.TYPE.GETSTATIC); - } - - if ((!Config.enableATHROW) && (instruction instanceof I_ATHROW)) { - throw new ClassParseException(instruction, ClassParseException.TYPE.ATHROW); - } - - if ((!Config.enableMONITOR) && ((instruction instanceof I_MONITORENTER) || (instruction instanceof I_MONITOREXIT))) { - throw new ClassParseException(instruction, ClassParseException.TYPE.SYNCHRONIZE); - } - - if ((!Config.enableNEW) && (instruction instanceof New)) { - throw new ClassParseException(instruction, ClassParseException.TYPE.NEW); - } - - if (instruction instanceof I_AASTORE) { - throw new ClassParseException(instruction, ClassParseException.TYPE.ARRAYALIAS); - } - - if ((!Config.enableSWITCH) && ((instruction instanceof I_LOOKUPSWITCH) || (instruction instanceof I_TABLESWITCH))) { - throw new ClassParseException(instruction, ClassParseException.TYPE.SWITCH); - } - - if (!Config.enableMETHODARRAYPASSING) { - if (instruction instanceof MethodCall) { - final MethodCall methodCall = (MethodCall) instruction; - - final MethodReferenceEntry methodReferenceEntry = methodCall.getConstantPoolMethodEntry(); - if (!Kernel.isMappedMethod(methodReferenceEntry)) { // we will allow trusted methods to violate this rule - for (final Arg arg : methodReferenceEntry.getArgs()) { - if (arg.isArray()) { - throw new ClassParseException(instruction, ClassParseException.TYPE.METHODARRAYARG); - } - } - } - } - } - - setRequiredPragmas(instruction); - - pcMap.put(pc, instruction); - - // list maintenance, make this the pcHead if pcHead is null - if (pcHead == null) { - pcHead = instruction; - } - - // extend the list of instructions here we make the new instruction point to previous tail - instruction.setPrevPC(pcTail); - - // if tail exists (not the first instruction in the list) link it to the new instruction - if (pcTail != null) { - pcTail.setNextPC(instruction); - } - - // now move the tail along - pcTail = instruction; - } - - return (pcMap); - } - - /** - * Here we connect the branch nodes to the instruction that they branch to. - * <p> - * Each branch node contains a 'target' field indended to reference the node that the branch targets. Each instruction also contain four seperate lists of branch nodes that reference it. - * These lists hold forwardConditional, forwardUnconditional, reverseConditional and revereseUnconditional branches that reference it. - * <p> - * So assuming that we had a branch node at pc offset 100 which represented 'goto 200'. - * <p> - * Following this call the branch node at pc offset 100 will have a 'target' field which actually references the instruction at pc offset 200, and the instruction at pc offset 200 will - * have the branch node (at 100) added to it's forwardUnconditional list. - * - * @see InstructionSet.Branch#getTarget() - */ - public void buildBranchGraphs(Map<Integer, Instruction> pcMap) { - for (Instruction instruction = pcHead; instruction != null; instruction = instruction.getNextPC()) { - if (instruction.isBranch()) { - final Branch branch = instruction.asBranch(); - final Instruction targetInstruction = pcMap.get(branch.getAbsolute()); - branch.setTarget(targetInstruction); - } - } - } - - /** - * Javac optimizes some branches to avoid goto->goto, branch->goto etc. - * - * This method specifically deals with reverse branches which are the result of such optimisations. - * - * <code><pre> - * - * </pre></code> - * - * - * - */ - public void deoptimizeReverseBranches() { - - for (Instruction instruction = pcHead; instruction != null; instruction = instruction.getNextPC()) { - if (instruction.isBranch()) { - final Branch branch = instruction.asBranch(); - if (branch.isReverse()) { - final Instruction target = branch.getTarget(); - final LinkedList<Branch> list = target.getReverseUnconditionalBranches(); - if ((list != null) && (list.size() > 0) && (list.get(list.size() - 1) != branch)) { - final Branch unconditional = list.get(list.size() - 1).asBranch(); - branch.retarget(unconditional); - - } - } - } - } - } - - /** - * DUP family of instructions break our stack unwind model (whereby we treat instructions like the oeprands they create/consume). - * - * <p> - * Here we replace DUP style instructions with a 'mock' instruction which 'clones' the effect of the instruction. This would be invalid to execute but is useful - * to replace the DUP with a 'pattern' which it simulates. This allows us to later apply transforms to represent the original code. - * - * <p> - * An example might be the bytecode for the following sequence. - * <code><pre> - * results[10]++; - return - * </pre></code> - * - * Which results in the following bytecode - * <code><pre> - 0: aload_0 // reference through 'this' to get - 1: getfield // field 'results' which is an array of int - 4: bipush 10 // push the array index - 6: dup2 // dreaded dup2 we'll come back here - 7: iaload // ignore for the moment. - 8: iconst_1 - 9: iadd - 10: iastore - 11: return - * </pre></code> - * - * First we need to know what the stack will look like before the dup2 is encountered. - * Using our folding technique we represent the first two instructions inside () - * - * <pre><code> - getfield (aload_0 // result in the array field reference on stack - bipush 10 // the array index - dup2 // dreaded dup2 we'll come back here - * </code></pre> - * - * The <code>dup2</code> essentially copies the top two elements on the stack. So we emulate this by replacing the dup2 with clones of the instructions which would reinstate the same stack state. - * <p> - * So after the <code>dup2</code> transform we end up with:- - * <pre><code> - getfield (aload_0) // result in the array field reference on stack - bipush 10 // the array index - {getfield (aload_0)} // result in the array field reference on stack - {bipush 10} // the array index - * </code></pre> - * - * So carrying on lets look at the <code>iaload</code> which consumes two operands (the index and the array field reference) and creates one (the result of an array access) - * - * <pre><code> - getfield (aload_0) // result in the array field reference on stack - bipush 10 // the array index - {getfield (aload_0)} // result in the array field reference on stack - {bipush 10} // the array index - iaload - * </code></pre> - * - * So we now have - * - * <pre><code> - getfield (aload_0) // result in the array field reference on stack - bipush 10 // the array index - iaload ({getfield(aload_0), {bipush 10}) // results in the array element on the stack - iconst - iadd - * </code></pre> - * - * And if you are following along the <code>iadd</code> will fold the previous two stack entries essentially pushing the result of - * <code>results[10]+1<code> on the stack. - * - * <pre><code> - getfield (aload_0) // result in the array field reference on stack - bipush 10 // the array index - iadd (iaload ({getfield(aload_0), {bipush 10}, iconst_1) // push of results[10]+1 - * </code></pre> - * Then the final <code>istore</code> instruction which consumes 3 stack operands (the field array reference, the index and the value to assign). - * - * <p> - * Which results in - * <pre><code> - istore (getfield (aload_0), bipush 10, iadd (iaload ({getfield(aload_0), {bipush 10}, iconst_1)) // results[10] = results[10+1] - * </code></pre> - * - * Where <code>results[10] = results[10+1]<code> is the long-hand form of the <code>results[10]++</code> - * and will be transformed by one of the 'inc' transforms to the more familiar form a little later. - * - * @param _expressionList - * @param _instruction - * @throws ClassParseException - */ - public void txFormDups(ExpressionList _expressionList, final Instruction _instruction) throws ClassParseException { - if (_instruction instanceof I_DUP) { - Instruction e = _expressionList.getTail(); - while (!e.producesStack()) { - e = e.getPrevExpr(); - } - - _expressionList.add(new CloneInstruction(this, e)); - System.out.println("clone of " + e); - } else if (_instruction instanceof I_DUP2) { - Instruction e = _expressionList.getTail(); - while (!e.producesStack()) { - e = e.getPrevPC(); - } - - final Instruction clone = e; - e = e.getPrevExpr(); - while (!e.producesStack()) { - e = e.getPrevExpr(); - } - - _expressionList.add(new CloneInstruction(this, e)); - _expressionList.add(new CloneInstruction(this, clone)); - } else if (_instruction instanceof I_DUP_X1) { - - Instruction e = _expressionList.getTail(); - - while (!e.producesStack()) { - e = e.getPrevExpr(); - } - final Instruction clone1 = new CloneInstruction(this, e); - e = e.getPrevExpr(); - while (!e.producesStack()) { - e = e.getPrevExpr(); - } - - _expressionList.insertBetween(e.getPrevExpr(), e, clone1); - - } else if (_instruction instanceof I_DUP_X2) { - - // dup_x2 duplicates top operand and jams a copy in 3 down from the top - // ...word3, word2, word1 => ...word1, word3, word2, word1 - - Instruction e = _expressionList.getTail(); - - if (logger.isLoggable(Level.FINE)) { - logger.fine("Found DUP_X2 prev=" + e.getPrevExpr() + " e=" + e + " curr=" + _instruction); - } - - // Get the previous instr to write to stack "word1" - while (!e.producesStack()) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("DUP_X2 skipping to find write: e=" + e); - } - e = e.getPrevExpr(); - } - - // Clone it, this will replace the dup action - final Instruction clone1 = new CloneInstruction(this, e); - - if (logger.isLoggable(Level.FINE)) { - logger.fine("DUP_X2 cloning: clone1=" + clone1); - } - - // Skip over 2 earlier writes to stack and capture 3rd one - e = e.getPrevExpr(); - - for (int i = 0; i < 2;) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("DUP_X2 skipping to find insert: e=" + e); - } - if (e.producesStack()) { - i++; - } - if (i < 2) { - e = e.getPrevExpr(); - } - } - - if (logger.isLoggable(Level.FINE)) { - logger.fine("DUP_X2 insert: prev=" + e.getPrevExpr() + " e=" + e + " clone=" + clone1); - } - - // Add our clone in between those two writes - _expressionList.insertBetween(e.getPrevExpr(), e, clone1); - - } else if (_instruction instanceof DUP) { - - throw new ClassParseException(_instruction, ClassParseException.TYPE.UNSUPPORTEDBYTECODE); - } - - } - - /** - * Try to fold the instructions into higher level structures. - * At the end we have a folded instruction tree with 'roots' containing the - * top level branches (stores mostly) - * @throws ClassParseException - */ - - void foldExpressions() throws ClassParseException { - - // we also populate a second list of expressions held between headTail.head and headTail.tail - - for (Instruction instruction = pcHead; instruction != null; instruction = instruction.getNextPC()) { - - // Here we are going to extract loop/if/structure from the list that we have collected so far in the roots list - // We are looking for a new instruction which is the target of a forward branch (this is why we collected forward branch counts) we only enter this loop - // however if roots list is not empty and it's tail is not a forward branch. - - expressionList.foldComposite(instruction); - - // If we find a DUP then we need to txform the DUP into a set of clones on the xpressionlist - if (instruction instanceof DUP) { - txFormDups(expressionList, instruction); - } else { - if (instruction.consumesStack()) { - // If instruction consumes n operands, then walk back until we find n roots on the xpressionlist that produce stack. - // we will user this cursor to track our progress - Instruction cursor = expressionList.getTail(); - - // set this flag if we pass something that does not produce stack - boolean foundNonStackProducer = false; - - // operandStart will points to the beginning of the list of consumed operands - Instruction operandStart = null; - - // back up from root tail past each instruction expecting to create a consumed operand for this instruction - for (int i = 0; i < instruction.getStackConsumeCount();) { - if (!cursor.producesStack()) { - foundNonStackProducer = true; // we spotted an instruction that does not consume stack. So we need to analyze this - } else { - i++; - } - operandStart = cursor; - cursor = cursor.getPrevExpr(); - } - - // if we found something that did not consume stack we probably have an expression with a side effect - - if (foundNonStackProducer) { - // Something like - // a = b++; - // foo(i++); - // return(a++); - // so we need to check for common transformations - applyTransformations(expressionList, instruction, operandStart); - } - - // cut the tail off and give it to instruction - final Instruction childTail = expressionList.getTail(); - final Instruction childHead = expressionList.createList(cursor); - - instruction.setChildren(childHead, childTail); - } - // add this instruction to the tail of roots - expressionList.add(instruction); - } - } - } - - InstructionTransformer[] transformers = new InstructionTransformer[] { - - new InstructionTransformer("long hand post increment of field"){ - - /** - * - * <pre><code> - * A A - * | | - * +1, 0 getfield<f> | - * | / getfield<f> Increment(fieldref<f>++) - * 0, 0 putfield<f> - iadd | - * | \ i_const_1 | - * B B - * - * A A - * | | - * +1, 0 getfield<f> | - * | / getfield<f> Increment(fieldRef<f>++) - * 0, 0 putfield<f> - i2<t> iadd | - * | \ i_const_1 | - * B B - * </code></pre> - */ - - @Override public Instruction transform(final ExpressionList _expressionList, final Instruction i) { - InstructionMatch result = null; - - if (Config.enablePUTFIELD - && (result = InstructionPattern.accessInstanceField.matches(i, InstructionPattern.assignToInstanceField)).ok) { - - final Instruction accessRaw = i; - final Instruction assignRaw = i.getNextExpr(); - final AccessInstanceField access = (AccessInstanceField) i.getReal(); - final AssignToInstanceField assign = (AssignToInstanceField) i.getNextExpr().getReal(); - if (access.getConstantPoolFieldIndex() == assign.getConstantPoolFieldIndex()) { - Instruction child = ((Instruction) assign).getFirstChild().getNextExpr(); - - if (child instanceof CastOperator) { - child = child.getFirstChild(); - } - if (child instanceof I_IADD) { - final I_IADD add = (I_IADD) child; - final Instruction lhs = add.getLhs(); - final Instruction rhs = add.getRhs(); - if (lhs instanceof AccessInstanceField) { - if (rhs instanceof I_ICONST_1) { - final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, - true, false); - _expressionList.replaceInclusive(accessRaw, assignRaw, inc); - return (inc); - } - } - } - } - } - return (null); - } - }, - new InstructionTransformer("long hand pre increment of field"){ - /** - * <pre> - * A A - * | | - * | / getfield<f> | - * +1, -2 iadd | - * | \ i_const_1 Increment(++fieldref<f>) - * | / getfield<f> | - * +0, -1 putfield<f> -- iadd | - * | \ i_const_1 | - * B B - * </pre> - */ - - @Override public Instruction transform(final ExpressionList _expressionList, final Instruction i) { - InstructionMatch result = null; - if (Config.enablePUTFIELD - && (result = InstructionPattern.fieldPlusOne.matches(i, InstructionPattern.assignToInstanceField)).ok) { - - final Instruction topAddRaw = i; - final Instruction assignRaw = i.getNextExpr(); - final I_IADD topAdd = (I_IADD) i.getReal(); - final AssignToInstanceField assign = (AssignToInstanceField) i.getNextExpr().getReal(); - final Instruction topLhs = topAdd.getLhs().getReal(); - final Instruction topRhs = topAdd.getRhs().getReal(); - if (topLhs instanceof AccessInstanceField) { - final AccessInstanceField topLhsAccess = (AccessInstanceField) topLhs; - if (topRhs instanceof I_ICONST_1) { - if (topLhsAccess.getConstantPoolFieldIndex() == assign.getConstantPoolFieldIndex()) { - final Instruction child = ((Instruction) assign).getFirstChild().getNextExpr(); - final Instruction valueToAssign = assign.getValueToAssign(); - if (valueToAssign instanceof I_IADD) { - - final I_IADD add = (I_IADD) child; - final Instruction lhs = add.getLhs(); - final Instruction rhs = add.getRhs(); - if (lhs instanceof AccessInstanceField) { - if (rhs instanceof I_ICONST_1) { - - final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, - (Instruction) topLhsAccess, true, true); - _expressionList.replaceInclusive(topAddRaw, assignRaw, inc); - - return (inc); - } - } - } - } - - } - } - - } - return (null); - } - }, - new InstructionTransformer("long hand post increment of local variable"){ - /** - * <pre> - * A A - * | | - * +1, 0 iload<n> | - * | / iload<n> Increment(varref<n>++) - * 0, 0 istore<n> - iadd | - * | \ i_const_1 | - * B B - * - * A A - * | | - * +1, 0 <t>load<n> | - * | / iload<n> Increment( varref<n>++) - * 0, 0 <t>store<n> - i2<t> iadd | - * | \ i_const_1 | - * B B - * </pre> - */ - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - // looking for a post increment on a local variable - InstructionMatch result = null; - if ((result = InstructionPattern.accessLocalVariable.matches(i, InstructionPattern.longHandIncLocalVariable)).ok) { - - final AccessLocalVariable access = (AccessLocalVariable) i; - final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); - if (access.getLocalVariableTableIndex() == assign.getLocalVariableTableIndex()) { - final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, true, false); - _expressionList.replaceInclusive((Instruction) access, (Instruction) assign, inc); - return (inc); - } - } - return (null); - } - - }, - new InstructionTransformer("long hand post decrement of local variable"){ - /** - * <pre> - * A A - * | | - * +1, 0 iload<n> | - * | / iload<n> Decrement(varref<n>--) - * 0, 0 istore<n> - isub | - * | \ i_const_1 | - * B B - * - * A A - * | | - * +1, 0 <t>load<n> | - * | / iload<n> Decrement( varref<n>--) - * 0, 0 <t>store<n> - i2<t> isub | - * | \ i_const_1 | - * B B - * </pre> - */ - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - if ((result = InstructionPattern.accessLocalVariable.matches(i, InstructionPattern.longHandDecLocalVariable)).ok) { - - final AccessLocalVariable access = (AccessLocalVariable) i; - final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); - if (access.getLocalVariableTableIndex() == assign.getLocalVariableTableIndex()) { - final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, false, false); - _expressionList.replaceInclusive((Instruction) access, (Instruction) assign, inc); - return (inc); - } - } - return (null); - } - - }, - new InstructionTransformer("long hand pre increment of local variable"){ - /** - * <pre> - * A A - * | / iload<n> | - * 0, 0 istore<n> - iadd | - * | \ i_const_1 Increment(++varref<n>) - * +1, 0 iload<n> | - * | | - * B B - * - * A A - * | / iload<n> | - * 0, 0 <t>store<n> - i2<t> iadd | - * | \ i_const_1 Increment( ++varref<n>) - * +1, 0 <t>load<n> | - * | | - * B B - * </pre> - */ - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - // pre increment local variable - if ((result = InstructionPattern.longHandIncLocalVariable.matches(i, InstructionPattern.accessLocalVariable)).ok) { - - final AssignToLocalVariable assign = (AssignToLocalVariable) i; - final AccessLocalVariable access = (AccessLocalVariable) i.getNextExpr(); - if (access.getLocalVariableTableIndex() == assign.getLocalVariableTableIndex()) { - final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, true, true); - _expressionList.replaceInclusive((Instruction) assign, (Instruction) access, inc); - return (inc); - } - - } - - return (null); - } - - }, - new InstructionTransformer("inline assign - say for methiod call or logical expression - "){ - /** - * <pre> - * A A - * | | - * 0, 0 iload<n> | - * | / iload<n> InlineAssign(istore<?>, iload<n>) - * +1, 0 istore<?> | - * | | - * B B - * </pre> - */ - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - - if ((result = InstructionPattern.accessLocalVariable.matches(i, InstructionPattern.assignToLocalVariable)).ok) { - - final AccessLocalVariable access = (AccessLocalVariable) i; - if (access.getLocalVariableTableIndex() != 0) { // we don;t want to trap on 'this' references ;) - final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); - if (access.getLocalVariableTableIndex() != assign.getLocalVariableTableIndex()) { - final InlineAssignInstruction inlineAssign = new InlineAssignInstruction(MethodModel.this, assign, - (Instruction) access); - _expressionList.replaceInclusive((Instruction) access, (Instruction) assign, inlineAssign); - return (inlineAssign); - } - } - } - - return (null); - } - - }, - new InstructionTransformer("pre increment of local variable"){ - - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - if ((result = InstructionPattern.inc.matches(i, InstructionPattern.accessLocalVariable)).ok) { - - final I_IINC iinc = (I_IINC) i; - final AccessLocalVariable access = (AccessLocalVariable) i.getNextExpr(); - if (iinc.getLocalVariableTableIndex() == access.getLocalVariableTableIndex()) { - - final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, - iinc.isInc(), true); - _expressionList.replaceInclusive(iinc, (Instruction) access, inc); - return (inc); - } - } - return (null); - } - - }, - new InstructionTransformer("post increment of local variable"){ - - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - - if ((result = InstructionPattern.accessLocalVariable.matches(i, InstructionPattern.inc)).ok) { - - final AccessLocalVariable access = (AccessLocalVariable) i; - final I_IINC iinc = (I_IINC) i.getNextExpr(); - - if (iinc.getLocalVariableTableIndex() == access.getLocalVariableTableIndex()) { - - final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, - iinc.isInc(), false); - _expressionList.replaceInclusive((Instruction) access, iinc, inc); - return (inc); - } - } - return (null); - } - - }, - new InstructionTransformer("inline assign of local variable (with cast)"){ - /** - * <pre> - * A A - * | /exp | - * 0, 0 cast<n> | - * | / iload<n> InlineAssign(istore<?>, cast) - * +1, 0 istore<?> | - * | | - * B B - * </pre> - */ - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - if ((result = InstructionPattern.cast.matches(i, InstructionPattern.assignToLocalVariable)).ok) { - - final CastOperator cast = (CastOperator) i; - - final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); - - final InlineAssignInstruction inlineAssign = new InlineAssignInstruction(MethodModel.this, assign, cast); - _expressionList.replaceInclusive((Instruction) cast, (Instruction) assign, inlineAssign); - return (inlineAssign); - - } - return (null); - } - - }, - new InstructionTransformer("field array element pre increment with nested index (local variable) pre increment"){ - /** - * <pre> - * A A - * | / getfield - aload | - * | / iaload | - * | / \ i_aload1 | - * iadd | - * | \ iconst 1 | - * | | - * | FieldArrayElementIncrement(pre) - * | / getfield - aload | - * iastore - iload | - * | \ [fieldArrayElementPlusOne] | - * | | - * B B - * </pre> - */ - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - if ((result = InstructionPattern.fieldArrayElementPlusOne.matches(i, - InstructionPattern.longHandFieldArrayElementIncrement)).ok) { - - final Instruction addRaw = i; - final Instruction assignArrayRaw = i.getNextExpr(); - // I_IADD add = (I_IADD) addRaw.getReal(); - final AssignToArrayElement assignArray = (AssignToArrayElement) assignArrayRaw.getReal(); - final FieldArrayElementIncrement inlineAssign = new FieldArrayElementIncrement(MethodModel.this, assignArray, - true, true); - _expressionList.replaceInclusive(addRaw, assignArrayRaw, inlineAssign); - return (inlineAssign); - - } - - return (null); - } - - }, - new InstructionTransformer("field array element pre decrement with nested index (local variable) pre decrement"){ - /** - * <pre> - * A A - * | / getfield - aload | - * | / iaload | - * | / \ i_aload1 | - * isub | - * | \ iconst 1 | - * | | - * | FieldArrayElementIncrement(pre) - * | / getfield - aload | - * iastore - iload | - * | \ [fieldArrayElementMinusOne] | - * | | - * B B - * </pre> - */ - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - if ((result = InstructionPattern.fieldArrayElementMinusOne.matches(i, - InstructionPattern.longHandFieldArrayElementDecrement)).ok) { - - final Instruction subRaw = i; - final Instruction assignArrayRaw = i.getNextExpr(); - // I_IADD add = (I_IADD) addRaw.getReal(); - final AssignToArrayElement assignArray = (AssignToArrayElement) assignArrayRaw.getReal(); - final FieldArrayElementIncrement inlineAssign = new FieldArrayElementIncrement(MethodModel.this, assignArray, - false, true); - _expressionList.replaceInclusive(subRaw, assignArrayRaw, inlineAssign); - return (inlineAssign); - - } - return (null); - } - - }, - new InstructionTransformer("field array element post inccrement with nested index (local variable) "){ - - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - if ((result = InstructionPattern.fieldArrayElementAccess.matches(i, - InstructionPattern.longHandFieldArrayElementIncrement)).ok) { - /** - * <pre> - * A A - * | / getfield<f> - aload | - * iaload | - * | \ i_load | - * | FieldArrayElementIncrement(post) - * | / getfield - aload | - * iastore - iload | - * | \ [fieldArrayElementPlusOne] | - * | | - * B B - * - * - * </pre> - */ - final Instruction accessArrayRaw = i; - final Instruction assignArrayRaw = i.getNextExpr(); - final AccessArrayElement accessArray = (AccessArrayElement) accessArrayRaw.getReal(); - final AssignToArrayElement assignArray = (AssignToArrayElement) assignArrayRaw.getReal(); - final AccessField accessField1 = (AccessField) accessArray.getArrayRef().getReal(); - final AccessField accessField2 = (AccessField) assignArray.getArrayRef().getReal(); - if (accessField1.getConstantPoolFieldIndex() == accessField2.getConstantPoolFieldIndex()) { - // we accessing the same field at least - //AccessLocalVariable accessLocalVariable1 = (AccessLocalVariable) accessArray.getArrayIndex().getReal(); - //AccessLocalVariable accessLocalVariable2 = (AccessLocalVariable) assignArray.getArrayIndex().getReal(); - // if (accessLocalVariable1.getLocalVariableTableIndex() == accessLocalVariable2.getLocalVariableTableIndex()) { - // and both arrays are referencing the array element using the same variable - final FieldArrayElementIncrement inlineAssign = new FieldArrayElementIncrement(MethodModel.this, assignArray, - true, false); - _expressionList.replaceInclusive(accessArrayRaw, assignArrayRaw, inlineAssign); - return (inlineAssign); - // } - } - - } - - return (null); - } - - }, - new InstructionTransformer("field array element post decrement with nested index (local variable) "){ - /** - * <pre> - * A A - * | / getfield<f> - aload | - * iaload | - * | \ i_load | - * | FieldArrayElementIncrement(post) - * | / getfield - aload | - * iastore - iload | - * | \ [fieldArrayElementMinusOne] | - * | | - * B B - * - * - * </pre> - */ - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - if ((result = InstructionPattern.fieldArrayElementAccess.matches(i, - InstructionPattern.longHandFieldArrayElementDecrement)).ok) { - - final Instruction accessArrayRaw = i; - final Instruction assignArrayRaw = i.getNextExpr(); - final AccessArrayElement accessArray = (AccessArrayElement) accessArrayRaw.getReal(); - final AssignToArrayElement assignArray = (AssignToArrayElement) assignArrayRaw.getReal(); - final AccessField accessField1 = (AccessField) accessArray.getArrayRef().getReal(); - final AccessField accessField2 = (AccessField) assignArray.getArrayRef().getReal(); - if (accessField1.getConstantPoolFieldIndex() == accessField2.getConstantPoolFieldIndex()) { - // we accessing the same field at least - final AccessLocalVariable accessLocalVariable1 = (AccessLocalVariable) accessArray.getArrayIndex().getReal(); - final AccessLocalVariable accessLocalVariable2 = (AccessLocalVariable) assignArray.getArrayIndex().getReal(); - if (accessLocalVariable1.getLocalVariableTableIndex() == accessLocalVariable2.getLocalVariableTableIndex()) { - // and both arrays are referencing the array element using the same variable - final FieldArrayElementIncrement inlineAssign = new FieldArrayElementIncrement(MethodModel.this, - assignArray, false, false); - _expressionList.replaceInclusive(accessArrayRaw, assignArrayRaw, inlineAssign); - return (inlineAssign); - } - } - - } - return (null); - } - - }, - new InstructionTransformer("inline assign (for method call or logical expression)"){ - /** - * <pre> - * A A - * | | - * 0, 0 invoke<n> | - * | / invoke() InlineAssign(istore<?>, invoke) - * +1, 0 istore<?> | - * | | - * B B - * </pre> - */ - - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - if ((result = InstructionPattern.methodCall.matches(i, InstructionPattern.assignToLocalVariable)).ok) { - - final Instruction invoke = i; - - final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); - - final InlineAssignInstruction inlineAssign = new InlineAssignInstruction(MethodModel.this, assign, invoke); - _expressionList.replaceInclusive(invoke, (Instruction) assign, inlineAssign); - return (inlineAssign); - - } - return (null); - } - - }, - new InstructionTransformer("incline assign from constant (method call or logical expression)"){ - /** - * <pre> - * A A - * | | - * 0, 0 invoke<n> | - * | / invoke() InlineAssign(istore<?>, invoke) - * +1, 0 istore<?> | - * | | - * B B - * </pre> - */ - - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - - if ((result = InstructionPattern.constant.matches(i, InstructionPattern.assignToLocalVariable)).ok) { - - final Instruction constant = i; - - final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); - - final InlineAssignInstruction inlineAssign = new InlineAssignInstruction(MethodModel.this, assign, constant); - _expressionList.replaceInclusive(constant, (Instruction) assign, inlineAssign); - return (inlineAssign); - - } - - return (null); - } - - }, - new InstructionTransformer("inline array assignment as part of a method call"){ - /** - * <pre> - * A A - * | | - * 0, 0 invoke<n> | - * | / invoke() InlineAssign(istore<?>, invoke) - * +1, 0 iastore<?> | - * | | - * B B - * </pre> - */ - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - if ((result = InstructionPattern.methodCall.matches(i, InstructionPattern.assignToArrayElement)).ok) { - - final Instruction invoke = i; - - final AssignToArrayElement assign = (AssignToArrayElement) i.getNextExpr(); - - final FieldArrayElementAssign inlineAssign = new FieldArrayElementAssign(MethodModel.this, assign, invoke); - _expressionList.replaceInclusive(invoke, assign, inlineAssign); - return (inlineAssign); - - } - - return (null); - } - - }, - new InstructionTransformer("inline array element increment as as part of a method call "){ - /** - * <pre> - * A A - * | | - * 0, 0 invoke<n> | - * | / invoke() InlineAssign(istore<?>, invoke) - * +1, 0 iastore<?> | - * | | - * B B - * </pre> - */ - @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { - - InstructionMatch result = null; - if ((result = InstructionPattern.assignToArrayElement.matches(i, - InstructionPattern.longHandFieldArrayElementIncrement)).ok) { - - final Instruction invoke = i; - - final AssignToArrayElement assign = (AssignToArrayElement) i.getNextExpr(); - - final FieldArrayElementAssign inlineAssign = new FieldArrayElementAssign(MethodModel.this, assign, invoke); - _expressionList.replaceInclusive(invoke, assign, inlineAssign); - - return (inlineAssign); - - } - - return (null); - } - - } - - }; - - void applyTransformations(ExpressionList _expressionList, final Instruction _instruction, final Instruction _operandStart) - throws ClassParseException { - - if (logger.isLoggable(Level.FINE)) { - - System.out.println("We are looking at " + _instruction + " which wants to consume " + _instruction.getStackConsumeCount() - + " operands"); - } - boolean txformed = false; - - /** - * Here we look for multi-assigns - * i.e - * - * a=b=c=<exp>; - */ - if ((_instruction instanceof AssignToLocalVariable) && _operandStart.producesStack() - && (_operandStart.getNextExpr() instanceof AssignToLocalVariable)) { - final Instruction assignFirst = _operandStart.getNextExpr(); - Instruction assign = assignFirst; - int count = 0; - while ((assign != null) && (assign instanceof AssignToLocalVariable)) { - assign = assign.getNextExpr(); - count++; - } - if (assign == null) { - final Instruction newOne = new MultiAssignInstruction(this, _operandStart, assignFirst, assign); - _expressionList.replaceInclusive(_operandStart, assign, newOne); - txformed = true; - } - } - - if (!txformed) { - boolean again = false; - for (Instruction i = _operandStart; i != null; i = again ? i : i.getNextExpr()) { - again = false; - - for (final InstructionTransformer txformer : transformers) { - final Instruction newI = txformer.transform(_expressionList, i); - if (newI != null) { - i = newI; - again = true; - txformed = true; - break; - } - } - - } - - } - - if (txformed) { - if (logger.isLoggable(Level.FINE)) { - - System.out.println("We are looking at " + _instruction + " which wants to consume " - + _instruction.getStackConsumeCount() + " operands"); - } - } else { - throw new ClassParseException(_instruction, ClassParseException.TYPE.OPERANDCONSUMERPRODUCERMISSMATCH); - } - - } - - /** - * Determine if this method is a getter and record the accessed field if so - */ - void checkForGetter(Map<Integer, Instruction> pcMap) throws ClassParseException { - final String methodName = getMethod().getName(); - String rawVarNameCandidate = null; - boolean mightBeGetter = true; - - if (methodName.startsWith("get")) { - rawVarNameCandidate = methodName.substring(3); - } else if (methodName.startsWith("is")) { - rawVarNameCandidate = methodName.substring(2); - } else { - mightBeGetter = false; - } - - // Getters should have 3 bcs: aload_0, getfield, ?return - if (mightBeGetter) { - boolean possiblySimpleGetImplementation = pcMap.size() == 3; - if ((rawVarNameCandidate != null) && (isNoCL() || possiblySimpleGetImplementation)) { - final String firstLetter = rawVarNameCandidate.substring(0, 1).toLowerCase(); - final String varNameCandidateCamelCased = rawVarNameCandidate.replaceFirst(rawVarNameCandidate.substring(0, 1), firstLetter); - String accessedFieldName; - - if (!isNoCL()) { - - Instruction instruction = expressionList.getHead(); - - if ((instruction instanceof Return) && (expressionList.getHead() == expressionList.getTail())) { - instruction = instruction.getPrevPC(); - if (instruction instanceof AccessInstanceField) { - final FieldEntry field = ((AccessInstanceField) instruction).getConstantPoolFieldEntry(); - accessedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - if (accessedFieldName.equals(varNameCandidateCamelCased)) { - - // Verify field type matches return type - final String fieldType = field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); - final String returnType = getMethod().getDescriptor().substring(2); - //System.out.println( "### field type = " + fieldType ); - //System.out.println( "### method args = " + returnType ); - assert (fieldType.length() == 1) && (returnType.length() == 1) : " can only use basic type getters"; - - // Allow isFoo style for boolean fields - if ((methodName.startsWith("is") && fieldType.equals("Z")) || (methodName.startsWith("get"))) { - if (fieldType.equals(returnType)) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Found " + methodName + " as a getter for " + varNameCandidateCamelCased.toLowerCase()); - } - - methodIsGetter = true; - setAccessorVariableFieldEntry(field); - assert methodIsSetter == false : " cannot be both"; - } else { - throw new ClassParseException(ClassParseException.TYPE.BADGETTERTYPEMISMATCH, methodName); - - } - } - } else { - throw new ClassParseException(ClassParseException.TYPE.BADGETTERNAMEMISMATCH, methodName); - } - } - } else { - throw new ClassParseException(ClassParseException.TYPE.BADGETTERNAMENOTFOUND, methodName); - } - } else { - FieldEntry fieldEntry = getMethod().getOwnerClassModel().getConstantPool().getFieldEntry(varNameCandidateCamelCased); - setAccessorVariableFieldEntry(fieldEntry); - if (getAccessorVariableFieldEntry() == null) { - throw new ClassParseException(ClassParseException.TYPE.BADGETTERNAMEMISMATCH, methodName); - } - methodIsGetter = true; - if (method.getClassModel().getPrivateMemorySize(fieldEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8()) != null) - { - methodIsPrivateMemoryGetter = true; - } - } - } else { - throw new ClassParseException(ClassParseException.TYPE.BADGETTERNAMENOTFOUND, methodName); - } - } - } - - private void setAccessorVariableFieldEntry(FieldEntry field) { - accessorVariableFieldEntry = field; - } - - /** - * Determine if this method is a setter and record the accessed field if so - */ - void checkForSetter(Map<Integer, Instruction> pcMap) throws ClassParseException { - final String methodName = getMethod().getName(); - if (methodName.startsWith("set")) { - final String rawVarNameCandidate = methodName.substring(3); - final String firstLetter = rawVarNameCandidate.substring(0, 1).toLowerCase(); - final String varNameCandidateCamelCased = rawVarNameCandidate.replaceFirst(rawVarNameCandidate.substring(0, 1), - firstLetter); - String accessedFieldName = null; - final Instruction instruction = expressionList.getHead(); - - // setters should be aload_0, ?load_1, putfield, return - if ((instruction instanceof AssignToInstanceField) && (expressionList.getTail() instanceof Return) && (pcMap.size() == 4)) { - final Instruction prev = instruction.getPrevPC(); - if (prev instanceof AccessLocalVariable) { - final FieldEntry field = ((AssignToInstanceField) instruction).getConstantPoolFieldEntry(); - accessedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - if (accessedFieldName.equals(varNameCandidateCamelCased)) { - - // Verify field type matches setter arg type - final String fieldType = field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); - final String setterArgType = getMethod().getDescriptor().substring(1, 2); - - //System.out.println( "### field type = " + fieldType ); - //System.out.println( "### setter type = " + setterArgType ); - assert fieldType.length() == 1 : " can only use basic type getters"; - - if (fieldType.equals(setterArgType)) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Found " + methodName + " as a setter for " + varNameCandidateCamelCased.toLowerCase() - + " of type " + fieldType); - } - - methodIsSetter = true; - setAccessorVariableFieldEntry(field); - - // Setters use putfield which will miss the normal store check - if (fieldType.equals("B") || fieldType.equals("Z")) { - usesByteWrites = true; - } - - assert methodIsGetter == false : " cannot be both"; - } else { - throw new ClassParseException(ClassParseException.TYPE.BADSETTERTYPEMISMATCH, methodName); - } - } else { - throw new ClassParseException(ClassParseException.TYPE.BADSETTERTYPEMISMATCH, methodName); - } - } - } - } - } - - // The entrypoint is used to make checks on object accessors - Entrypoint entrypoint = null; - - MethodModel(ClassModelMethod _method, Entrypoint _entrypoint) throws AparapiException { - entrypoint = _entrypoint; - init(_method); - } - - MethodModel(ClassModelMethod _method) throws AparapiException { - init(_method); - } - - public static class FakeLocalVariableTableEntry implements LocalVariableTableEntry<LocalVariableInfo>{ - - class Var implements LocalVariableInfo{ - - int startPc = 0; - - int endPc = 0; - - String name = null; - - boolean arg; - - String descriptor = ""; - - int slotIndex; - - Var(StoreSpec _storeSpec, int _slotIndex, int _startPc, boolean _arg) { - slotIndex = _slotIndex; - arg = _arg; - startPc = _startPc; - if (_storeSpec.equals(StoreSpec.A)) { - name = "arr_" + _slotIndex; - descriptor = "/* arg */"; - } else { - name = _storeSpec.toString().toLowerCase() + "_" + _slotIndex; - descriptor = _storeSpec.toString(); - } - } - - Var() { - name = "NONE"; - } - - @Override public boolean equals(Object object) { - return (object instanceof Var && ((object == this) || ((Var) object).name.equals(name))); - } - - public String toString() { - return (name + "[" + startPc + "-" + endPc + "]"); - } - - @Override public boolean isArray() { - return name.startsWith("arr"); - } - - @Override public int getStart() { - return startPc; - } - - @Override public int getEnd() { - return endPc; - } - - @Override public int getLength() { - return endPc - startPc; - } - - @Override public String getVariableName() { - return (name); - } - - @Override public String getVariableDescriptor() { - return (descriptor); - } - - @Override public int getVariableIndex() { - return (slotIndex); - } - } - - List<LocalVariableInfo> list = new ArrayList<LocalVariableInfo>(); - - public FakeLocalVariableTableEntry(Map<Integer, Instruction> _pcMap, ClassModelMethod _method) { - int numberOfSlots = _method.getCodeEntry().getMaxLocals(); - - MethodDescription description = ClassModel.getMethodDescription(_method.getDescriptor()); - String[] args = description.getArgs(); - - int thisOffset = _method.isStatic() ? 0 : 1; - - Var[] vars = new Var[numberOfSlots + thisOffset]; - StoreSpec[] argsAsStoreSpecs = new StoreSpec[args.length + thisOffset]; - if (thisOffset == 1) { - argsAsStoreSpecs[0] = StoreSpec.O; - vars[0] = new Var(argsAsStoreSpecs[0], 0, 0, true); - list.add(vars[0]); - - } - for (int i = 0; i < args.length; i++) { - if (args[i].startsWith("[")) { - argsAsStoreSpecs[i + thisOffset] = StoreSpec.A; - } else { - argsAsStoreSpecs[i + thisOffset] = StoreSpec.valueOf(args[i].substring(0, 1)); - } - vars[i + thisOffset] = new Var(argsAsStoreSpecs[i + thisOffset], i + thisOffset, 0, true); - list.add(vars[i + thisOffset]); - } - for (int i = args.length + thisOffset; i < numberOfSlots + thisOffset; i++) { - vars[i] = new Var(); - } - - int pc = 0; - Instruction instruction = null; - for (Entry<Integer, Instruction> entry : _pcMap.entrySet()) { - - pc = entry.getKey(); - instruction = entry.getValue(); - StoreSpec storeSpec = instruction.getByteCode().getStore(); - - if (storeSpec != StoreSpec.NONE) { - int slotIndex = ((InstructionSet.LocalVariableTableIndexAccessor) instruction).getLocalVariableTableIndex(); - Var prevVar = vars[slotIndex]; - Var var = new Var(storeSpec, slotIndex, pc + instruction.getLength(), false); // will get collected pretty soon if this is not the same as the previous in this slot - if (!prevVar.equals(var)) { - prevVar.endPc = pc; - vars[slotIndex] = var; - list.add(vars[slotIndex]); - } - } - } - for (int i = 0; i < numberOfSlots + thisOffset; i++) { - vars[i].endPc = pc + instruction.getLength(); - } - - Collections.sort(list, new Comparator<LocalVariableInfo>(){ - @Override public int compare(LocalVariableInfo o1, LocalVariableInfo o2) { - return o1.getStart() - o2.getStart(); - } - }); - - if (Config.enableShowFakeLocalVariableTable) { - System.out.println("FakeLocalVariableTable:"); - System.out.println(" Start Length Slot Name Signature"); - for (LocalVariableInfo lvi : list) { - Var var = (Var) lvi; - System.out.println(String.format(" %5d %5d %4d %8s %s", var.startPc, var.getLength(), var.slotIndex, - var.name, var.descriptor)); - } - } - } - - @Override public LocalVariableInfo getVariable(int _pc, int _index) { - LocalVariableInfo returnValue = null; - // System.out.println("pc = " + _pc + " index = " + _index); - for (LocalVariableInfo localVariableInfo : list) { - // System.out.println(" start=" + localVariableInfo.getStart() + " length=" + localVariableInfo.getLength() - // + " varidx=" + localVariableInfo.getVariableIndex()); - if (_pc >= localVariableInfo.getStart() - 1 && _pc <= (localVariableInfo.getStart() + localVariableInfo.getLength()) - && _index == localVariableInfo.getVariableIndex()) { - returnValue = localVariableInfo; - break; - } - } - return (returnValue); - } - - @Override public Iterator<LocalVariableInfo> iterator() { - return list.iterator(); - } - - } - - private void init(ClassModelMethod _method) throws AparapiException { - try { - method = _method; - expressionList = new ExpressionList(this); - ClassModel owner = _method.getOwnerClassModel(); - if (owner.getNoCLMethods().contains(method.getName())) { - noCL = true; - } - - // check if we have any exception handlers - final int exceptionsSize = method.getCodeEntry().getExceptionPoolEntries().size(); - if (exceptionsSize > 0) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("exception size for " + method + " = " + exceptionsSize); - } - throw new ClassParseException(ClassParseException.TYPE.EXCEPTION); - } - - // check if we have any local variables which are arrays. This is an attempt to avoid aliasing field arrays - - // We are going to make 4 passes. - - // Pass #1 create a linked list of instructions from head to tail - final Map<Integer, Instruction> pcMap = createListOfInstructions(); - - LocalVariableTableEntry<LocalVariableInfo> localVariableTableEntry = method.getLocalVariableTableEntry(); - if (localVariableTableEntry == null) { - localVariableTableEntry = new FakeLocalVariableTableEntry(pcMap, method); - method.setLocalVariableTableEntry(localVariableTableEntry); - logger.warning("Method " - + method.getName() - + method.getDescriptor() - + " does not contain a LocalVariableTable entry (source not compiled with -g) aparapi will attempt to create a synthetic table based on bytecode. This is experimental!!"); - } - - // pass #2 build branch graph - buildBranchGraphs(pcMap); - - // pass #3 build branch graph - deoptimizeReverseBranches(); - - // pass #4 - - foldExpressions(); - - // Accessor conversion only works on member object arrays - if (isNoCL() || (entrypoint != null) && (_method.getClassModel() != entrypoint.getClassModel())) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Considering accessor call: " + getName()); - } - checkForGetter(pcMap); - checkForSetter(pcMap); - } - - // In order to allow inline access of object member fields, postpone this check - //if ((!Config.enablePUTFIELD) && usesPutfield && !isSetter()) { - // throw new ClassParseException("We don't support putfield instructions beyond simple setters"); - //} - - if (logger.isLoggable(Level.FINE)) { - logger.fine("end \n" + expressionList.dumpDiagram(null)); - } - if (Config.instructionListener != null) { - Config.instructionListener.showAndTell("end", expressionList.getHead(), null); - } - } catch (final Throwable _t) { - if (_t instanceof ClassParseException) { - _t.printStackTrace(); - throw (ClassParseException) _t; - } - throw new ClassParseException(_t); - - } - } - - public LocalVariableTableEntry<LocalVariableInfo> getLocalVariableTableEntry() { - return (method.getLocalVariableTableEntry()); - } - - public ConstantPool getConstantPool() { - return (method.getConstantPool()); - } - - public LocalVariableInfo getLocalVariable(int _pc, int _index) { - return (method.getLocalVariable(_pc, _index)); - } - - public String getSimpleName() { - return (method.getName()); - } - - /* - * @return the fully qualified name such as "com_amd_javalabs_opencl_demo_PaternityTest$SimpleKernel__actuallyDoIt" - */ - public String getName() { - return (method.getClassModel().getMethod(method.getName(), method.getDescriptor()).getClassModel().getClassWeAreModelling() - .getName().replace('.', '_') - + "__" + method.getName()); - } - - public String getReturnType() { - final String returnType = method.getDescriptorUTF8Entry().getUTF8(); - final int index = returnType.indexOf(")"); - return (returnType.substring(index + 1)); - } - - public List<MethodCall> getMethodCalls() { - final List<MethodCall> methodCalls = new ArrayList<MethodCall>(); - - for (Instruction i = getPCHead(); i != null; i = i.getNextPC()) { - if (i instanceof MethodCall) { - final MethodCall methodCall = (MethodCall) i; - methodCalls.add(methodCall); - } - } - return (methodCalls); - } - - public Instruction getPCHead() { - return (pcHead); - } - - public Instruction getExprHead() { - return (expressionList.getHead()); - } - - @Override public String toString() { - return "MethodModel of " + method; - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + + */ +package com.aparapi.internal.model; + +import com.aparapi.*; +import com.aparapi.internal.exception.*; +import com.aparapi.internal.instruction.*; +import com.aparapi.internal.instruction.InstructionPattern.*; +import com.aparapi.internal.instruction.InstructionSet.*; +import com.aparapi.internal.model.ClassModel.*; +import com.aparapi.internal.model.ClassModel.ConstantPool.*; +import com.aparapi.internal.model.ClassModel.ConstantPool.MethodReferenceEntry.*; +import com.aparapi.internal.reader.*; + +import java.util.*; +import java.util.Map.Entry; +import java.util.logging.*; + +public class MethodModel{ + + private static Logger logger = Logger.getLogger(Config.getLoggerName()); + + private ExpressionList expressionList; + + private ClassModelMethod method; + + /** + True is an indication to use the fp64 pragma + */ + private boolean usesDoubles; + + /** + True is an indication to use the byte addressable store pragma + */ + private boolean usesByteWrites; + + private boolean methodIsGetter; + + private boolean methodIsSetter; + + private boolean methodIsPrivateMemoryGetter = false; + + // Only setters can use putfield + private boolean usesPutfield; + + private FieldEntry accessorVariableFieldEntry; + + private boolean noCL = false; + + public boolean isGetter() { + return methodIsGetter; + } + + public boolean isSetter() { + return methodIsSetter; + } + + public boolean methodUsesPutfield() { + return usesPutfield; + } + + public boolean isNoCL() { + return noCL; + } + + public boolean isPrivateMemoryGetter() { + return methodIsPrivateMemoryGetter; + } + + public ClassModelMethod getMethod() { + return method; + } + + public FieldEntry getAccessorVariableFieldEntry() { + return accessorVariableFieldEntry; + } + + private final Set<MethodModel> calledMethods = new HashSet<MethodModel>(); + + public Set<MethodModel> getCalledMethods() { + return calledMethods; + } + + public void checkForRecursion(Set<MethodModel> transitiveCalledMethods) throws AparapiException { + + if (transitiveCalledMethods.contains(this)) { + throw new ClassParseException(ClassParseException.TYPE.RECURSION, getName()); + } + + // Add myself + transitiveCalledMethods.add(this); + + // For each callee, send him a copy of the call chain up to this method + final Iterator<MethodModel> cmi = getCalledMethods().iterator(); + while (cmi.hasNext()) { + final MethodModel next = cmi.next(); + next.checkForRecursion(transitiveCalledMethods); + } + + // Done examining this call path, remove myself + transitiveCalledMethods.remove(this); + } + + /** + * After we have folded the top level instructions this root list will contain a list of all of the 'root' instructions (stores/loops/conditionals) + * We are going to build a linked list. Here we track the head and tail + */ + private Instruction pcTail = null; + + private Instruction pcHead = null; + + /** + * Look at each instruction for use of long/double or byte writes which + * require pragmas to be used in the OpenCL source + * + */ + public void setRequiredPragmas(Instruction instruction) { + final boolean setDouble = instruction.getByteCode().usesDouble(); + if (setDouble) { + usesDoubles = true; + if (logger.isLoggable(Level.FINE)) { + logger.fine("Found D on =" + instruction + " in " + getName()); + } + } + + if ((instruction instanceof I_BASTORE) || (instruction instanceof I_CASTORE /* || instruction instanceof I_SASTORE */)) { + usesByteWrites = true; + if (usesByteWrites && logger.isLoggable(Level.FINE)) { + logger.fine("Found Byte Addressable Store on =" + instruction + " in " + getName()); + } + } + } + + public boolean requiresDoublePragma() { + return usesDoubles; + } + + public boolean requiresByteAddressableStorePragma() { + return usesByteWrites; + } + + /** + * Create a linked list of instructions (from pcHead to pcTail). + * + * Returns a map of int (pc) to Instruction which to allow us to quickly get from a bytecode offset to the appropriate instruction. + * + * Note that not all int values from 0 to code.length values will map to a valid instruction, if pcMap.get(n) == null then this implies + * that 'n' is not the start of an instruction + * + * So either pcMap.get(i)== null or pcMap.get(i).getThisPC()==i + * + * @return Map<Integer, Instruction> the returned pc to Instruction map + */ + public Map<Integer, Instruction> createListOfInstructions() throws ClassParseException { + final Map<Integer, Instruction> pcMap = new LinkedHashMap<Integer, Instruction>(); + final byte[] code = method.getCode(); + + // We create a byteReader for reading the bytes from the code array + final ByteReader codeReader = new ByteReader(code); + while (codeReader.hasMore()) { + // Create an instruction from code reader's current position + final int pc = codeReader.getOffset(); + final Instruction instruction = InstructionSet.ByteCode.create(this, codeReader); + + if ((!Config.enablePUTFIELD) && (instruction instanceof I_PUTFIELD)) { + // Special case putfield handling to allow object setter processing + // and bail later if necessary + //throw new ClassParseException("We don't support putfield instructions"); + usesPutfield = true; + } + + if ((!Config.enableARETURN) && (instruction instanceof I_ARETURN)) { + throw new ClassParseException(instruction, ClassParseException.TYPE.ARRAY_RETURN); + } + + if ((!Config.enablePUTSTATIC) && (instruction instanceof I_PUTSTATIC)) { + throw new ClassParseException(instruction, ClassParseException.TYPE.PUTFIELD); + } + + if ((!Config.enableINVOKEINTERFACE) && (instruction instanceof I_INVOKEINTERFACE)) { + throw new ClassParseException(instruction, ClassParseException.TYPE.INVOKEINTERFACE); + } + + if ((!Config.enableGETSTATIC) && (instruction instanceof I_GETSTATIC)) { + throw new ClassParseException(instruction, ClassParseException.TYPE.GETSTATIC); + } + + if ((!Config.enableATHROW) && (instruction instanceof I_ATHROW)) { + throw new ClassParseException(instruction, ClassParseException.TYPE.ATHROW); + } + + if ((!Config.enableMONITOR) && ((instruction instanceof I_MONITORENTER) || (instruction instanceof I_MONITOREXIT))) { + throw new ClassParseException(instruction, ClassParseException.TYPE.SYNCHRONIZE); + } + + if ((!Config.enableNEW) && (instruction instanceof New)) { + throw new ClassParseException(instruction, ClassParseException.TYPE.NEW); + } + + if (instruction instanceof I_AASTORE) { + throw new ClassParseException(instruction, ClassParseException.TYPE.ARRAYALIAS); + } + + if ((!Config.enableSWITCH) && ((instruction instanceof I_LOOKUPSWITCH) || (instruction instanceof I_TABLESWITCH))) { + throw new ClassParseException(instruction, ClassParseException.TYPE.SWITCH); + } + + if (!Config.enableMETHODARRAYPASSING) { + if (instruction instanceof MethodCall) { + final MethodCall methodCall = (MethodCall) instruction; + + final MethodReferenceEntry methodReferenceEntry = methodCall.getConstantPoolMethodEntry(); + if (!Kernel.isMappedMethod(methodReferenceEntry)) { // we will allow trusted methods to violate this rule + for (final Arg arg : methodReferenceEntry.getArgs()) { + if (arg.isArray()) { + throw new ClassParseException(instruction, ClassParseException.TYPE.METHODARRAYARG); + } + } + } + } + } + + setRequiredPragmas(instruction); + + pcMap.put(pc, instruction); + + // list maintenance, make this the pcHead if pcHead is null + if (pcHead == null) { + pcHead = instruction; + } + + // extend the list of instructions here we make the new instruction point to previous tail + instruction.setPrevPC(pcTail); + + // if tail exists (not the first instruction in the list) link it to the new instruction + if (pcTail != null) { + pcTail.setNextPC(instruction); + } + + // now move the tail along + pcTail = instruction; + } + + return (pcMap); + } + + /** + * Here we connect the branch nodes to the instruction that they branch to. + * <p> + * Each branch node contains a 'target' field indended to reference the node that the branch targets. Each instruction also contain four seperate lists of branch nodes that reference it. + * These lists hold forwardConditional, forwardUnconditional, reverseConditional and revereseUnconditional branches that reference it. + * <p> + * So assuming that we had a branch node at pc offset 100 which represented 'goto 200'. + * <p> + * Following this call the branch node at pc offset 100 will have a 'target' field which actually references the instruction at pc offset 200, and the instruction at pc offset 200 will + * have the branch node (at 100) added to it's forwardUnconditional list. + * + * @see InstructionSet.Branch#getTarget() + */ + public void buildBranchGraphs(Map<Integer, Instruction> pcMap) { + for (Instruction instruction = pcHead; instruction != null; instruction = instruction.getNextPC()) { + if (instruction.isBranch()) { + final Branch branch = instruction.asBranch(); + final Instruction targetInstruction = pcMap.get(branch.getAbsolute()); + branch.setTarget(targetInstruction); + } + } + } + + /** + * Javac optimizes some branches to avoid goto->goto, branch->goto etc. + * + * This method specifically deals with reverse branches which are the result of such optimisations. + * + * <code><pre> + * + * </pre></code> + * + * + * + */ + public void deoptimizeReverseBranches() { + + for (Instruction instruction = pcHead; instruction != null; instruction = instruction.getNextPC()) { + if (instruction.isBranch()) { + final Branch branch = instruction.asBranch(); + if (branch.isReverse()) { + final Instruction target = branch.getTarget(); + final LinkedList<Branch> list = target.getReverseUnconditionalBranches(); + if ((list != null) && (list.size() > 0) && (list.get(list.size() - 1) != branch)) { + final Branch unconditional = list.get(list.size() - 1).asBranch(); + branch.retarget(unconditional); + + } + } + } + } + } + + /** + * DUP family of instructions break our stack unwind model (whereby we treat instructions like the oeprands they create/consume). + * + * <p> + * Here we replace DUP style instructions with a 'mock' instruction which 'clones' the effect of the instruction. This would be invalid to execute but is useful + * to replace the DUP with a 'pattern' which it simulates. This allows us to later apply transforms to represent the original code. + * + * <p> + * An example might be the bytecode for the following sequence. + * <code><pre> + * results[10]++; + return + * </pre></code> + * + * Which results in the following bytecode + * <code><pre> + 0: aload_0 // reference through 'this' to get + 1: getfield // field 'results' which is an array of int + 4: bipush 10 // push the array index + 6: dup2 // dreaded dup2 we'll come back here + 7: iaload // ignore for the moment. + 8: iconst_1 + 9: iadd + 10: iastore + 11: return + * </pre></code> + * + * First we need to know what the stack will look like before the dup2 is encountered. + * Using our folding technique we represent the first two instructions inside () + * + * <pre><code> + getfield (aload_0 // result in the array field reference on stack + bipush 10 // the array index + dup2 // dreaded dup2 we'll come back here + * </code></pre> + * + * The <code>dup2</code> essentially copies the top two elements on the stack. So we emulate this by replacing the dup2 with clones of the instructions which would reinstate the same stack state. + * <p> + * So after the <code>dup2</code> transform we end up with:- + * <pre><code> + getfield (aload_0) // result in the array field reference on stack + bipush 10 // the array index + {getfield (aload_0)} // result in the array field reference on stack + {bipush 10} // the array index + * </code></pre> + * + * So carrying on lets look at the <code>iaload</code> which consumes two operands (the index and the array field reference) and creates one (the result of an array access) + * + * <pre><code> + getfield (aload_0) // result in the array field reference on stack + bipush 10 // the array index + {getfield (aload_0)} // result in the array field reference on stack + {bipush 10} // the array index + iaload + * </code></pre> + * + * So we now have + * + * <pre><code> + getfield (aload_0) // result in the array field reference on stack + bipush 10 // the array index + iaload ({getfield(aload_0), {bipush 10}) // results in the array element on the stack + iconst + iadd + * </code></pre> + * + * And if you are following along the <code>iadd</code> will fold the previous two stack entries essentially pushing the result of + * <code>results[10]+1<code> on the stack. + * + * <pre><code> + getfield (aload_0) // result in the array field reference on stack + bipush 10 // the array index + iadd (iaload ({getfield(aload_0), {bipush 10}, iconst_1) // push of results[10]+1 + * </code></pre> + * Then the final <code>istore</code> instruction which consumes 3 stack operands (the field array reference, the index and the value to assign). + * + * <p> + * Which results in + * <pre><code> + istore (getfield (aload_0), bipush 10, iadd (iaload ({getfield(aload_0), {bipush 10}, iconst_1)) // results[10] = results[10+1] + * </code></pre> + * + * Where <code>results[10] = results[10+1]<code> is the long-hand form of the <code>results[10]++</code> + * and will be transformed by one of the 'inc' transforms to the more familiar form a little later. + * + * @param _expressionList + * @param _instruction + * @throws ClassParseException + */ + public void txFormDups(ExpressionList _expressionList, final Instruction _instruction) throws ClassParseException { + if (_instruction instanceof I_DUP) { + Instruction e = _expressionList.getTail(); + while (!e.producesStack()) { + e = e.getPrevExpr(); + } + + _expressionList.add(new CloneInstruction(this, e)); + System.out.println("clone of " + e); + } else if (_instruction instanceof I_DUP2) { + Instruction e = _expressionList.getTail(); + while (!e.producesStack()) { + e = e.getPrevPC(); + } + + final Instruction clone = e; + e = e.getPrevExpr(); + while (!e.producesStack()) { + e = e.getPrevExpr(); + } + + _expressionList.add(new CloneInstruction(this, e)); + _expressionList.add(new CloneInstruction(this, clone)); + } else if (_instruction instanceof I_DUP_X1) { + + Instruction e = _expressionList.getTail(); + + while (!e.producesStack()) { + e = e.getPrevExpr(); + } + final Instruction clone1 = new CloneInstruction(this, e); + e = e.getPrevExpr(); + while (!e.producesStack()) { + e = e.getPrevExpr(); + } + + _expressionList.insertBetween(e.getPrevExpr(), e, clone1); + + } else if (_instruction instanceof I_DUP_X2) { + + // dup_x2 duplicates top operand and jams a copy in 3 down from the top + // ...word3, word2, word1 => ...word1, word3, word2, word1 + + Instruction e = _expressionList.getTail(); + + if (logger.isLoggable(Level.FINE)) { + logger.fine("Found DUP_X2 prev=" + e.getPrevExpr() + " e=" + e + " curr=" + _instruction); + } + + // Get the previous instr to write to stack "word1" + while (!e.producesStack()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("DUP_X2 skipping to find write: e=" + e); + } + e = e.getPrevExpr(); + } + + // Clone it, this will replace the dup action + final Instruction clone1 = new CloneInstruction(this, e); + + if (logger.isLoggable(Level.FINE)) { + logger.fine("DUP_X2 cloning: clone1=" + clone1); + } + + // Skip over 2 earlier writes to stack and capture 3rd one + e = e.getPrevExpr(); + + for (int i = 0; i < 2;) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("DUP_X2 skipping to find insert: e=" + e); + } + if (e.producesStack()) { + i++; + } + if (i < 2) { + e = e.getPrevExpr(); + } + } + + if (logger.isLoggable(Level.FINE)) { + logger.fine("DUP_X2 insert: prev=" + e.getPrevExpr() + " e=" + e + " clone=" + clone1); + } + + // Add our clone in between those two writes + _expressionList.insertBetween(e.getPrevExpr(), e, clone1); + + } else if (_instruction instanceof DUP) { + + throw new ClassParseException(_instruction, ClassParseException.TYPE.UNSUPPORTEDBYTECODE); + } + + } + + /** + * Try to fold the instructions into higher level structures. + * At the end we have a folded instruction tree with 'roots' containing the + * top level branches (stores mostly) + * @throws ClassParseException + */ + + void foldExpressions() throws ClassParseException { + + // we also populate a second list of expressions held between headTail.head and headTail.tail + + for (Instruction instruction = pcHead; instruction != null; instruction = instruction.getNextPC()) { + + // Here we are going to extract loop/if/structure from the list that we have collected so far in the roots list + // We are looking for a new instruction which is the target of a forward branch (this is why we collected forward branch counts) we only enter this loop + // however if roots list is not empty and it's tail is not a forward branch. + + expressionList.foldComposite(instruction); + + // If we find a DUP then we need to txform the DUP into a set of clones on the xpressionlist + if (instruction instanceof DUP) { + txFormDups(expressionList, instruction); + } else { + if (instruction.consumesStack()) { + // If instruction consumes n operands, then walk back until we find n roots on the xpressionlist that produce stack. + // we will user this cursor to track our progress + Instruction cursor = expressionList.getTail(); + + // set this flag if we pass something that does not produce stack + boolean foundNonStackProducer = false; + + // operandStart will points to the beginning of the list of consumed operands + Instruction operandStart = null; + + // back up from root tail past each instruction expecting to create a consumed operand for this instruction + for (int i = 0; i < instruction.getStackConsumeCount();) { + if (!cursor.producesStack()) { + foundNonStackProducer = true; // we spotted an instruction that does not consume stack. So we need to analyze this + } else { + i++; + } + operandStart = cursor; + cursor = cursor.getPrevExpr(); + } + + // if we found something that did not consume stack we probably have an expression with a side effect + + if (foundNonStackProducer) { + // Something like + // a = b++; + // foo(i++); + // return(a++); + // so we need to check for common transformations + applyTransformations(expressionList, instruction, operandStart); + } + + // cut the tail off and give it to instruction + final Instruction childTail = expressionList.getTail(); + final Instruction childHead = expressionList.createList(cursor); + + instruction.setChildren(childHead, childTail); + } + // add this instruction to the tail of roots + expressionList.add(instruction); + } + } + } + + InstructionTransformer[] transformers = new InstructionTransformer[] { + + new InstructionTransformer("long hand post increment of field"){ + + /** + * + * <pre><code> + * A A + * | | + * +1, 0 getfield<f> | + * | / getfield<f> Increment(fieldref<f>++) + * 0, 0 putfield<f> - iadd | + * | \ i_const_1 | + * B B + * + * A A + * | | + * +1, 0 getfield<f> | + * | / getfield<f> Increment(fieldRef<f>++) + * 0, 0 putfield<f> - i2<t> iadd | + * | \ i_const_1 | + * B B + * </code></pre> + */ + + @Override public Instruction transform(final ExpressionList _expressionList, final Instruction i) { + InstructionMatch result = null; + + if (Config.enablePUTFIELD + && (result = InstructionPattern.accessInstanceField.matches(i, InstructionPattern.assignToInstanceField)).ok) { + + final Instruction accessRaw = i; + final Instruction assignRaw = i.getNextExpr(); + final AccessInstanceField access = (AccessInstanceField) i.getReal(); + final AssignToInstanceField assign = (AssignToInstanceField) i.getNextExpr().getReal(); + if (access.getConstantPoolFieldIndex() == assign.getConstantPoolFieldIndex()) { + Instruction child = ((Instruction) assign).getFirstChild().getNextExpr(); + + if (child instanceof CastOperator) { + child = child.getFirstChild(); + } + if (child instanceof I_IADD) { + final I_IADD add = (I_IADD) child; + final Instruction lhs = add.getLhs(); + final Instruction rhs = add.getRhs(); + if (lhs instanceof AccessInstanceField) { + if (rhs instanceof I_ICONST_1) { + final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, + true, false); + _expressionList.replaceInclusive(accessRaw, assignRaw, inc); + return (inc); + } + } + } + } + } + return (null); + } + }, + new InstructionTransformer("long hand pre increment of field"){ + /** + * <pre> + * A A + * | | + * | / getfield<f> | + * +1, -2 iadd | + * | \ i_const_1 Increment(++fieldref<f>) + * | / getfield<f> | + * +0, -1 putfield<f> -- iadd | + * | \ i_const_1 | + * B B + * </pre> + */ + + @Override public Instruction transform(final ExpressionList _expressionList, final Instruction i) { + InstructionMatch result = null; + if (Config.enablePUTFIELD + && (result = InstructionPattern.fieldPlusOne.matches(i, InstructionPattern.assignToInstanceField)).ok) { + + final Instruction topAddRaw = i; + final Instruction assignRaw = i.getNextExpr(); + final I_IADD topAdd = (I_IADD) i.getReal(); + final AssignToInstanceField assign = (AssignToInstanceField) i.getNextExpr().getReal(); + final Instruction topLhs = topAdd.getLhs().getReal(); + final Instruction topRhs = topAdd.getRhs().getReal(); + if (topLhs instanceof AccessInstanceField) { + final AccessInstanceField topLhsAccess = (AccessInstanceField) topLhs; + if (topRhs instanceof I_ICONST_1) { + if (topLhsAccess.getConstantPoolFieldIndex() == assign.getConstantPoolFieldIndex()) { + final Instruction child = ((Instruction) assign).getFirstChild().getNextExpr(); + final Instruction valueToAssign = assign.getValueToAssign(); + if (valueToAssign instanceof I_IADD) { + + final I_IADD add = (I_IADD) child; + final Instruction lhs = add.getLhs(); + final Instruction rhs = add.getRhs(); + if (lhs instanceof AccessInstanceField) { + if (rhs instanceof I_ICONST_1) { + + final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, + (Instruction) topLhsAccess, true, true); + _expressionList.replaceInclusive(topAddRaw, assignRaw, inc); + + return (inc); + } + } + } + } + + } + } + + } + return (null); + } + }, + new InstructionTransformer("long hand post increment of local variable"){ + /** + * <pre> + * A A + * | | + * +1, 0 iload<n> | + * | / iload<n> Increment(varref<n>++) + * 0, 0 istore<n> - iadd | + * | \ i_const_1 | + * B B + * + * A A + * | | + * +1, 0 <t>load<n> | + * | / iload<n> Increment( varref<n>++) + * 0, 0 <t>store<n> - i2<t> iadd | + * | \ i_const_1 | + * B B + * </pre> + */ + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + // looking for a post increment on a local variable + InstructionMatch result = null; + if ((result = InstructionPattern.accessLocalVariable.matches(i, InstructionPattern.longHandIncLocalVariable)).ok) { + + final AccessLocalVariable access = (AccessLocalVariable) i; + final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); + if (access.getLocalVariableTableIndex() == assign.getLocalVariableTableIndex()) { + final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, true, false); + _expressionList.replaceInclusive((Instruction) access, (Instruction) assign, inc); + return (inc); + } + } + return (null); + } + + }, + new InstructionTransformer("long hand post decrement of local variable"){ + /** + * <pre> + * A A + * | | + * +1, 0 iload<n> | + * | / iload<n> Decrement(varref<n>--) + * 0, 0 istore<n> - isub | + * | \ i_const_1 | + * B B + * + * A A + * | | + * +1, 0 <t>load<n> | + * | / iload<n> Decrement( varref<n>--) + * 0, 0 <t>store<n> - i2<t> isub | + * | \ i_const_1 | + * B B + * </pre> + */ + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + if ((result = InstructionPattern.accessLocalVariable.matches(i, InstructionPattern.longHandDecLocalVariable)).ok) { + + final AccessLocalVariable access = (AccessLocalVariable) i; + final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); + if (access.getLocalVariableTableIndex() == assign.getLocalVariableTableIndex()) { + final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, false, false); + _expressionList.replaceInclusive((Instruction) access, (Instruction) assign, inc); + return (inc); + } + } + return (null); + } + + }, + new InstructionTransformer("long hand pre increment of local variable"){ + /** + * <pre> + * A A + * | / iload<n> | + * 0, 0 istore<n> - iadd | + * | \ i_const_1 Increment(++varref<n>) + * +1, 0 iload<n> | + * | | + * B B + * + * A A + * | / iload<n> | + * 0, 0 <t>store<n> - i2<t> iadd | + * | \ i_const_1 Increment( ++varref<n>) + * +1, 0 <t>load<n> | + * | | + * B B + * </pre> + */ + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + // pre increment local variable + if ((result = InstructionPattern.longHandIncLocalVariable.matches(i, InstructionPattern.accessLocalVariable)).ok) { + + final AssignToLocalVariable assign = (AssignToLocalVariable) i; + final AccessLocalVariable access = (AccessLocalVariable) i.getNextExpr(); + if (access.getLocalVariableTableIndex() == assign.getLocalVariableTableIndex()) { + final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, true, true); + _expressionList.replaceInclusive((Instruction) assign, (Instruction) access, inc); + return (inc); + } + + } + + return (null); + } + + }, + new InstructionTransformer("inline assign - say for methiod call or logical expression - "){ + /** + * <pre> + * A A + * | | + * 0, 0 iload<n> | + * | / iload<n> InlineAssign(istore<?>, iload<n>) + * +1, 0 istore<?> | + * | | + * B B + * </pre> + */ + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + + if ((result = InstructionPattern.accessLocalVariable.matches(i, InstructionPattern.assignToLocalVariable)).ok) { + + final AccessLocalVariable access = (AccessLocalVariable) i; + if (access.getLocalVariableTableIndex() != 0) { // we don;t want to trap on 'this' references ;) + final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); + if (access.getLocalVariableTableIndex() != assign.getLocalVariableTableIndex()) { + final InlineAssignInstruction inlineAssign = new InlineAssignInstruction(MethodModel.this, assign, + (Instruction) access); + _expressionList.replaceInclusive((Instruction) access, (Instruction) assign, inlineAssign); + return (inlineAssign); + } + } + } + + return (null); + } + + }, + new InstructionTransformer("pre increment of local variable"){ + + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + if ((result = InstructionPattern.inc.matches(i, InstructionPattern.accessLocalVariable)).ok) { + + final I_IINC iinc = (I_IINC) i; + final AccessLocalVariable access = (AccessLocalVariable) i.getNextExpr(); + if (iinc.getLocalVariableTableIndex() == access.getLocalVariableTableIndex()) { + + final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, + iinc.isInc(), true); + _expressionList.replaceInclusive(iinc, (Instruction) access, inc); + return (inc); + } + } + return (null); + } + + }, + new InstructionTransformer("post increment of local variable"){ + + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + + if ((result = InstructionPattern.accessLocalVariable.matches(i, InstructionPattern.inc)).ok) { + + final AccessLocalVariable access = (AccessLocalVariable) i; + final I_IINC iinc = (I_IINC) i.getNextExpr(); + + if (iinc.getLocalVariableTableIndex() == access.getLocalVariableTableIndex()) { + + final IncrementInstruction inc = new IncrementInstruction(MethodModel.this, (Instruction) access, + iinc.isInc(), false); + _expressionList.replaceInclusive((Instruction) access, iinc, inc); + return (inc); + } + } + return (null); + } + + }, + new InstructionTransformer("inline assign of local variable (with cast)"){ + /** + * <pre> + * A A + * | /exp | + * 0, 0 cast<n> | + * | / iload<n> InlineAssign(istore<?>, cast) + * +1, 0 istore<?> | + * | | + * B B + * </pre> + */ + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + if ((result = InstructionPattern.cast.matches(i, InstructionPattern.assignToLocalVariable)).ok) { + + final CastOperator cast = (CastOperator) i; + + final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); + + final InlineAssignInstruction inlineAssign = new InlineAssignInstruction(MethodModel.this, assign, cast); + _expressionList.replaceInclusive((Instruction) cast, (Instruction) assign, inlineAssign); + return (inlineAssign); + + } + return (null); + } + + }, + new InstructionTransformer("field array element pre increment with nested index (local variable) pre increment"){ + /** + * <pre> + * A A + * | / getfield - aload | + * | / iaload | + * | / \ i_aload1 | + * iadd | + * | \ iconst 1 | + * | | + * | FieldArrayElementIncrement(pre) + * | / getfield - aload | + * iastore - iload | + * | \ [fieldArrayElementPlusOne] | + * | | + * B B + * </pre> + */ + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + if ((result = InstructionPattern.fieldArrayElementPlusOne.matches(i, + InstructionPattern.longHandFieldArrayElementIncrement)).ok) { + + final Instruction addRaw = i; + final Instruction assignArrayRaw = i.getNextExpr(); + // I_IADD add = (I_IADD) addRaw.getReal(); + final AssignToArrayElement assignArray = (AssignToArrayElement) assignArrayRaw.getReal(); + final FieldArrayElementIncrement inlineAssign = new FieldArrayElementIncrement(MethodModel.this, assignArray, + true, true); + _expressionList.replaceInclusive(addRaw, assignArrayRaw, inlineAssign); + return (inlineAssign); + + } + + return (null); + } + + }, + new InstructionTransformer("field array element pre decrement with nested index (local variable) pre decrement"){ + /** + * <pre> + * A A + * | / getfield - aload | + * | / iaload | + * | / \ i_aload1 | + * isub | + * | \ iconst 1 | + * | | + * | FieldArrayElementIncrement(pre) + * | / getfield - aload | + * iastore - iload | + * | \ [fieldArrayElementMinusOne] | + * | | + * B B + * </pre> + */ + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + if ((result = InstructionPattern.fieldArrayElementMinusOne.matches(i, + InstructionPattern.longHandFieldArrayElementDecrement)).ok) { + + final Instruction subRaw = i; + final Instruction assignArrayRaw = i.getNextExpr(); + // I_IADD add = (I_IADD) addRaw.getReal(); + final AssignToArrayElement assignArray = (AssignToArrayElement) assignArrayRaw.getReal(); + final FieldArrayElementIncrement inlineAssign = new FieldArrayElementIncrement(MethodModel.this, assignArray, + false, true); + _expressionList.replaceInclusive(subRaw, assignArrayRaw, inlineAssign); + return (inlineAssign); + + } + return (null); + } + + }, + new InstructionTransformer("field array element post inccrement with nested index (local variable) "){ + + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + if ((result = InstructionPattern.fieldArrayElementAccess.matches(i, + InstructionPattern.longHandFieldArrayElementIncrement)).ok) { + /** + * <pre> + * A A + * | / getfield<f> - aload | + * iaload | + * | \ i_load | + * | FieldArrayElementIncrement(post) + * | / getfield - aload | + * iastore - iload | + * | \ [fieldArrayElementPlusOne] | + * | | + * B B + * + * + * </pre> + */ + final Instruction accessArrayRaw = i; + final Instruction assignArrayRaw = i.getNextExpr(); + final AccessArrayElement accessArray = (AccessArrayElement) accessArrayRaw.getReal(); + final AssignToArrayElement assignArray = (AssignToArrayElement) assignArrayRaw.getReal(); + final AccessField accessField1 = (AccessField) accessArray.getArrayRef().getReal(); + final AccessField accessField2 = (AccessField) assignArray.getArrayRef().getReal(); + if (accessField1.getConstantPoolFieldIndex() == accessField2.getConstantPoolFieldIndex()) { + // we accessing the same field at least + //AccessLocalVariable accessLocalVariable1 = (AccessLocalVariable) accessArray.getArrayIndex().getReal(); + //AccessLocalVariable accessLocalVariable2 = (AccessLocalVariable) assignArray.getArrayIndex().getReal(); + // if (accessLocalVariable1.getLocalVariableTableIndex() == accessLocalVariable2.getLocalVariableTableIndex()) { + // and both arrays are referencing the array element using the same variable + final FieldArrayElementIncrement inlineAssign = new FieldArrayElementIncrement(MethodModel.this, assignArray, + true, false); + _expressionList.replaceInclusive(accessArrayRaw, assignArrayRaw, inlineAssign); + return (inlineAssign); + // } + } + + } + + return (null); + } + + }, + new InstructionTransformer("field array element post decrement with nested index (local variable) "){ + /** + * <pre> + * A A + * | / getfield<f> - aload | + * iaload | + * | \ i_load | + * | FieldArrayElementIncrement(post) + * | / getfield - aload | + * iastore - iload | + * | \ [fieldArrayElementMinusOne] | + * | | + * B B + * + * + * </pre> + */ + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + if ((result = InstructionPattern.fieldArrayElementAccess.matches(i, + InstructionPattern.longHandFieldArrayElementDecrement)).ok) { + + final Instruction accessArrayRaw = i; + final Instruction assignArrayRaw = i.getNextExpr(); + final AccessArrayElement accessArray = (AccessArrayElement) accessArrayRaw.getReal(); + final AssignToArrayElement assignArray = (AssignToArrayElement) assignArrayRaw.getReal(); + final AccessField accessField1 = (AccessField) accessArray.getArrayRef().getReal(); + final AccessField accessField2 = (AccessField) assignArray.getArrayRef().getReal(); + if (accessField1.getConstantPoolFieldIndex() == accessField2.getConstantPoolFieldIndex()) { + // we accessing the same field at least + final AccessLocalVariable accessLocalVariable1 = (AccessLocalVariable) accessArray.getArrayIndex().getReal(); + final AccessLocalVariable accessLocalVariable2 = (AccessLocalVariable) assignArray.getArrayIndex().getReal(); + if (accessLocalVariable1.getLocalVariableTableIndex() == accessLocalVariable2.getLocalVariableTableIndex()) { + // and both arrays are referencing the array element using the same variable + final FieldArrayElementIncrement inlineAssign = new FieldArrayElementIncrement(MethodModel.this, + assignArray, false, false); + _expressionList.replaceInclusive(accessArrayRaw, assignArrayRaw, inlineAssign); + return (inlineAssign); + } + } + + } + return (null); + } + + }, + new InstructionTransformer("inline assign (for method call or logical expression)"){ + /** + * <pre> + * A A + * | | + * 0, 0 invoke<n> | + * | / invoke() InlineAssign(istore<?>, invoke) + * +1, 0 istore<?> | + * | | + * B B + * </pre> + */ + + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + if ((result = InstructionPattern.methodCall.matches(i, InstructionPattern.assignToLocalVariable)).ok) { + + final Instruction invoke = i; + + final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); + + final InlineAssignInstruction inlineAssign = new InlineAssignInstruction(MethodModel.this, assign, invoke); + _expressionList.replaceInclusive(invoke, (Instruction) assign, inlineAssign); + return (inlineAssign); + + } + return (null); + } + + }, + new InstructionTransformer("incline assign from constant (method call or logical expression)"){ + /** + * <pre> + * A A + * | | + * 0, 0 invoke<n> | + * | / invoke() InlineAssign(istore<?>, invoke) + * +1, 0 istore<?> | + * | | + * B B + * </pre> + */ + + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + + if ((result = InstructionPattern.constant.matches(i, InstructionPattern.assignToLocalVariable)).ok) { + + final Instruction constant = i; + + final AssignToLocalVariable assign = (AssignToLocalVariable) i.getNextExpr(); + + final InlineAssignInstruction inlineAssign = new InlineAssignInstruction(MethodModel.this, assign, constant); + _expressionList.replaceInclusive(constant, (Instruction) assign, inlineAssign); + return (inlineAssign); + + } + + return (null); + } + + }, + new InstructionTransformer("inline array assignment as part of a method call"){ + /** + * <pre> + * A A + * | | + * 0, 0 invoke<n> | + * | / invoke() InlineAssign(istore<?>, invoke) + * +1, 0 iastore<?> | + * | | + * B B + * </pre> + */ + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + if ((result = InstructionPattern.methodCall.matches(i, InstructionPattern.assignToArrayElement)).ok) { + + final Instruction invoke = i; + + final AssignToArrayElement assign = (AssignToArrayElement) i.getNextExpr(); + + final FieldArrayElementAssign inlineAssign = new FieldArrayElementAssign(MethodModel.this, assign, invoke); + _expressionList.replaceInclusive(invoke, assign, inlineAssign); + return (inlineAssign); + + } + + return (null); + } + + }, + new InstructionTransformer("inline array element increment as as part of a method call "){ + /** + * <pre> + * A A + * | | + * 0, 0 invoke<n> | + * | / invoke() InlineAssign(istore<?>, invoke) + * +1, 0 iastore<?> | + * | | + * B B + * </pre> + */ + @Override public Instruction transform(ExpressionList _expressionList, Instruction i) { + + InstructionMatch result = null; + if ((result = InstructionPattern.assignToArrayElement.matches(i, + InstructionPattern.longHandFieldArrayElementIncrement)).ok) { + + final Instruction invoke = i; + + final AssignToArrayElement assign = (AssignToArrayElement) i.getNextExpr(); + + final FieldArrayElementAssign inlineAssign = new FieldArrayElementAssign(MethodModel.this, assign, invoke); + _expressionList.replaceInclusive(invoke, assign, inlineAssign); + + return (inlineAssign); + + } + + return (null); + } + + } + + }; + + void applyTransformations(ExpressionList _expressionList, final Instruction _instruction, final Instruction _operandStart) + throws ClassParseException { + + if (logger.isLoggable(Level.FINE)) { + + System.out.println("We are looking at " + _instruction + " which wants to consume " + _instruction.getStackConsumeCount() + + " operands"); + } + boolean txformed = false; + + /** + * Here we look for multi-assigns + * i.e + * + * a=b=c=<exp>; + */ + if ((_instruction instanceof AssignToLocalVariable) && _operandStart.producesStack() + && (_operandStart.getNextExpr() instanceof AssignToLocalVariable)) { + final Instruction assignFirst = _operandStart.getNextExpr(); + Instruction assign = assignFirst; + int count = 0; + while ((assign != null) && (assign instanceof AssignToLocalVariable)) { + assign = assign.getNextExpr(); + count++; + } + if (assign == null) { + final Instruction newOne = new MultiAssignInstruction(this, _operandStart, assignFirst, assign); + _expressionList.replaceInclusive(_operandStart, assign, newOne); + txformed = true; + } + } + + if (!txformed) { + boolean again = false; + for (Instruction i = _operandStart; i != null; i = again ? i : i.getNextExpr()) { + again = false; + + for (final InstructionTransformer txformer : transformers) { + final Instruction newI = txformer.transform(_expressionList, i); + if (newI != null) { + i = newI; + again = true; + txformed = true; + break; + } + } + + } + + } + + if (txformed) { + if (logger.isLoggable(Level.FINE)) { + + System.out.println("We are looking at " + _instruction + " which wants to consume " + + _instruction.getStackConsumeCount() + " operands"); + } + } else { + throw new ClassParseException(_instruction, ClassParseException.TYPE.OPERANDCONSUMERPRODUCERMISSMATCH); + } + + } + + /** + * Determine if this method is a getter and record the accessed field if so + */ + void checkForGetter(Map<Integer, Instruction> pcMap) throws ClassParseException { + final String methodName = getMethod().getName(); + String rawVarNameCandidate = null; + boolean mightBeGetter = true; + + if (methodName.startsWith("get")) { + rawVarNameCandidate = methodName.substring(3); + } else if (methodName.startsWith("is")) { + rawVarNameCandidate = methodName.substring(2); + } else { + mightBeGetter = false; + } + + // Getters should have 3 bcs: aload_0, getfield, ?return + if (mightBeGetter) { + boolean possiblySimpleGetImplementation = pcMap.size() == 3; + if ((rawVarNameCandidate != null) && (isNoCL() || possiblySimpleGetImplementation)) { + final String firstLetter = rawVarNameCandidate.substring(0, 1).toLowerCase(); + final String varNameCandidateCamelCased = rawVarNameCandidate.replaceFirst(rawVarNameCandidate.substring(0, 1), firstLetter); + String accessedFieldName; + + if (!isNoCL()) { + + Instruction instruction = expressionList.getHead(); + + if ((instruction instanceof Return) && (expressionList.getHead() == expressionList.getTail())) { + instruction = instruction.getPrevPC(); + if (instruction instanceof AccessInstanceField) { + final FieldEntry field = ((AccessInstanceField) instruction).getConstantPoolFieldEntry(); + accessedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + if (accessedFieldName.equals(varNameCandidateCamelCased)) { + + // Verify field type matches return type + final String fieldType = field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); + final String returnType = getMethod().getDescriptor().substring(2); + //System.out.println( "### field type = " + fieldType ); + //System.out.println( "### method args = " + returnType ); + assert (fieldType.length() == 1) && (returnType.length() == 1) : " can only use basic type getters"; + + // Allow isFoo style for boolean fields + if ((methodName.startsWith("is") && fieldType.equals("Z")) || (methodName.startsWith("get"))) { + if (fieldType.equals(returnType)) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Found " + methodName + " as a getter for " + varNameCandidateCamelCased.toLowerCase()); + } + + methodIsGetter = true; + setAccessorVariableFieldEntry(field); + assert methodIsSetter == false : " cannot be both"; + } else { + throw new ClassParseException(ClassParseException.TYPE.BADGETTERTYPEMISMATCH, methodName); + + } + } + } else { + throw new ClassParseException(ClassParseException.TYPE.BADGETTERNAMEMISMATCH, methodName); + } + } + } else { + throw new ClassParseException(ClassParseException.TYPE.BADGETTERNAMENOTFOUND, methodName); + } + } else { + FieldEntry fieldEntry = getMethod().getOwnerClassModel().getConstantPool().getFieldEntry(varNameCandidateCamelCased); + setAccessorVariableFieldEntry(fieldEntry); + if (getAccessorVariableFieldEntry() == null) { + throw new ClassParseException(ClassParseException.TYPE.BADGETTERNAMEMISMATCH, methodName); + } + methodIsGetter = true; + if (method.getClassModel().getPrivateMemorySize(fieldEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8()) != null) + { + methodIsPrivateMemoryGetter = true; + } + } + } else { + throw new ClassParseException(ClassParseException.TYPE.BADGETTERNAMENOTFOUND, methodName); + } + } + } + + private void setAccessorVariableFieldEntry(FieldEntry field) { + accessorVariableFieldEntry = field; + } + + /** + * Determine if this method is a setter and record the accessed field if so + */ + void checkForSetter(Map<Integer, Instruction> pcMap) throws ClassParseException { + final String methodName = getMethod().getName(); + if (methodName.startsWith("set")) { + final String rawVarNameCandidate = methodName.substring(3); + final String firstLetter = rawVarNameCandidate.substring(0, 1).toLowerCase(); + final String varNameCandidateCamelCased = rawVarNameCandidate.replaceFirst(rawVarNameCandidate.substring(0, 1), + firstLetter); + String accessedFieldName = null; + final Instruction instruction = expressionList.getHead(); + + // setters should be aload_0, ?load_1, putfield, return + if ((instruction instanceof AssignToInstanceField) && (expressionList.getTail() instanceof Return) && (pcMap.size() == 4)) { + final Instruction prev = instruction.getPrevPC(); + if (prev instanceof AccessLocalVariable) { + final FieldEntry field = ((AssignToInstanceField) instruction).getConstantPoolFieldEntry(); + accessedFieldName = field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + if (accessedFieldName.equals(varNameCandidateCamelCased)) { + + // Verify field type matches setter arg type + final String fieldType = field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); + final String setterArgType = getMethod().getDescriptor().substring(1, 2); + + //System.out.println( "### field type = " + fieldType ); + //System.out.println( "### setter type = " + setterArgType ); + assert fieldType.length() == 1 : " can only use basic type getters"; + + if (fieldType.equals(setterArgType)) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Found " + methodName + " as a setter for " + varNameCandidateCamelCased.toLowerCase() + + " of type " + fieldType); + } + + methodIsSetter = true; + setAccessorVariableFieldEntry(field); + + // Setters use putfield which will miss the normal store check + if (fieldType.equals("B") || fieldType.equals("Z")) { + usesByteWrites = true; + } + + assert methodIsGetter == false : " cannot be both"; + } else { + throw new ClassParseException(ClassParseException.TYPE.BADSETTERTYPEMISMATCH, methodName); + } + } else { + throw new ClassParseException(ClassParseException.TYPE.BADSETTERTYPEMISMATCH, methodName); + } + } + } + } + } + + // The entrypoint is used to make checks on object accessors + Entrypoint entrypoint = null; + + MethodModel(ClassModelMethod _method, Entrypoint _entrypoint) throws AparapiException { + entrypoint = _entrypoint; + init(_method); + } + + MethodModel(ClassModelMethod _method) throws AparapiException { + init(_method); + } + + public static class FakeLocalVariableTableEntry implements LocalVariableTableEntry<LocalVariableInfo>{ + + class Var implements LocalVariableInfo{ + + int startPc = 0; + + int endPc = 0; + + String name = null; + + boolean arg; + + String descriptor = ""; + + int slotIndex; + + Var(StoreSpec _storeSpec, int _slotIndex, int _startPc, boolean _arg) { + slotIndex = _slotIndex; + arg = _arg; + startPc = _startPc; + if (_storeSpec.equals(StoreSpec.A)) { + name = "arr_" + _slotIndex; + descriptor = "/* arg */"; + } else { + name = _storeSpec.toString().toLowerCase() + "_" + _slotIndex; + descriptor = _storeSpec.toString(); + } + } + + Var() { + name = "NONE"; + } + + @Override public boolean equals(Object object) { + return (object instanceof Var && ((object == this) || ((Var) object).name.equals(name))); + } + + public String toString() { + return (name + "[" + startPc + "-" + endPc + "]"); + } + + @Override public boolean isArray() { + return name.startsWith("arr"); + } + + @Override public int getStart() { + return startPc; + } + + @Override public int getEnd() { + return endPc; + } + + @Override public int getLength() { + return endPc - startPc; + } + + @Override public String getVariableName() { + return (name); + } + + @Override public String getVariableDescriptor() { + return (descriptor); + } + + @Override public int getVariableIndex() { + return (slotIndex); + } + } + + List<LocalVariableInfo> list = new ArrayList<LocalVariableInfo>(); + + public FakeLocalVariableTableEntry(Map<Integer, Instruction> _pcMap, ClassModelMethod _method) { + int numberOfSlots = _method.getCodeEntry().getMaxLocals(); + + MethodDescription description = ClassModel.getMethodDescription(_method.getDescriptor()); + String[] args = description.getArgs(); + + int thisOffset = _method.isStatic() ? 0 : 1; + + Var[] vars = new Var[numberOfSlots + thisOffset]; + StoreSpec[] argsAsStoreSpecs = new StoreSpec[args.length + thisOffset]; + if (thisOffset == 1) { + argsAsStoreSpecs[0] = StoreSpec.O; + vars[0] = new Var(argsAsStoreSpecs[0], 0, 0, true); + list.add(vars[0]); + + } + for (int i = 0; i < args.length; i++) { + if (args[i].startsWith("[")) { + argsAsStoreSpecs[i + thisOffset] = StoreSpec.A; + } else { + argsAsStoreSpecs[i + thisOffset] = StoreSpec.valueOf(args[i].substring(0, 1)); + } + vars[i + thisOffset] = new Var(argsAsStoreSpecs[i + thisOffset], i + thisOffset, 0, true); + list.add(vars[i + thisOffset]); + } + for (int i = args.length + thisOffset; i < numberOfSlots + thisOffset; i++) { + vars[i] = new Var(); + } + + int pc = 0; + Instruction instruction = null; + for (Entry<Integer, Instruction> entry : _pcMap.entrySet()) { + + pc = entry.getKey(); + instruction = entry.getValue(); + StoreSpec storeSpec = instruction.getByteCode().getStore(); + + if (storeSpec != StoreSpec.NONE) { + int slotIndex = ((InstructionSet.LocalVariableTableIndexAccessor) instruction).getLocalVariableTableIndex(); + Var prevVar = vars[slotIndex]; + Var var = new Var(storeSpec, slotIndex, pc + instruction.getLength(), false); // will get collected pretty soon if this is not the same as the previous in this slot + if (!prevVar.equals(var)) { + prevVar.endPc = pc; + vars[slotIndex] = var; + list.add(vars[slotIndex]); + } + } + } + for (int i = 0; i < numberOfSlots + thisOffset; i++) { + vars[i].endPc = pc + instruction.getLength(); + } + + Collections.sort(list, new Comparator<LocalVariableInfo>(){ + @Override public int compare(LocalVariableInfo o1, LocalVariableInfo o2) { + return o1.getStart() - o2.getStart(); + } + }); + + if (Config.enableShowFakeLocalVariableTable) { + System.out.println("FakeLocalVariableTable:"); + System.out.println(" Start Length Slot Name Signature"); + for (LocalVariableInfo lvi : list) { + Var var = (Var) lvi; + System.out.println(String.format(" %5d %5d %4d %8s %s", var.startPc, var.getLength(), var.slotIndex, + var.name, var.descriptor)); + } + } + } + + @Override public LocalVariableInfo getVariable(int _pc, int _index) { + LocalVariableInfo returnValue = null; + // System.out.println("pc = " + _pc + " index = " + _index); + for (LocalVariableInfo localVariableInfo : list) { + // System.out.println(" start=" + localVariableInfo.getStart() + " length=" + localVariableInfo.getLength() + // + " varidx=" + localVariableInfo.getVariableIndex()); + if (_pc >= localVariableInfo.getStart() - 1 && _pc <= (localVariableInfo.getStart() + localVariableInfo.getLength()) + && _index == localVariableInfo.getVariableIndex()) { + returnValue = localVariableInfo; + break; + } + } + return (returnValue); + } + + @Override public Iterator<LocalVariableInfo> iterator() { + return list.iterator(); + } + + } + + private void init(ClassModelMethod _method) throws AparapiException { + try { + method = _method; + expressionList = new ExpressionList(this); + ClassModel owner = _method.getOwnerClassModel(); + if (owner.getNoCLMethods().contains(method.getName())) { + noCL = true; + } + + // check if we have any exception handlers + final int exceptionsSize = method.getCodeEntry().getExceptionPoolEntries().size(); + if (exceptionsSize > 0) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("exception size for " + method + " = " + exceptionsSize); + } + throw new ClassParseException(ClassParseException.TYPE.EXCEPTION); + } + + // check if we have any local variables which are arrays. This is an attempt to avoid aliasing field arrays + + // We are going to make 4 passes. + + // Pass #1 create a linked list of instructions from head to tail + final Map<Integer, Instruction> pcMap = createListOfInstructions(); + + LocalVariableTableEntry<LocalVariableInfo> localVariableTableEntry = method.getLocalVariableTableEntry(); + if (localVariableTableEntry == null) { + localVariableTableEntry = new FakeLocalVariableTableEntry(pcMap, method); + method.setLocalVariableTableEntry(localVariableTableEntry); + logger.warning("Method " + + method.getName() + + method.getDescriptor() + + " does not contain a LocalVariableTable entry (source not compiled with -g) aparapi will attempt to create a synthetic table based on bytecode. This is experimental!!"); + } + + // pass #2 build branch graph + buildBranchGraphs(pcMap); + + // pass #3 build branch graph + deoptimizeReverseBranches(); + + // pass #4 + + foldExpressions(); + + // Accessor conversion only works on member object arrays + if (isNoCL() || (entrypoint != null) && (_method.getClassModel() != entrypoint.getClassModel())) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Considering accessor call: " + getName()); + } + checkForGetter(pcMap); + checkForSetter(pcMap); + } + + // In order to allow inline access of object member fields, postpone this check + //if ((!Config.enablePUTFIELD) && usesPutfield && !isSetter()) { + // throw new ClassParseException("We don't support putfield instructions beyond simple setters"); + //} + + if (logger.isLoggable(Level.FINE)) { + logger.fine("end \n" + expressionList.dumpDiagram(null)); + } + if (Config.instructionListener != null) { + Config.instructionListener.showAndTell("end", expressionList.getHead(), null); + } + } catch (final Throwable _t) { + if (_t instanceof ClassParseException) { + _t.printStackTrace(); + throw (ClassParseException) _t; + } + throw new ClassParseException(_t); + + } + } + + public LocalVariableTableEntry<LocalVariableInfo> getLocalVariableTableEntry() { + return (method.getLocalVariableTableEntry()); + } + + public ConstantPool getConstantPool() { + return (method.getConstantPool()); + } + + public LocalVariableInfo getLocalVariable(int _pc, int _index) { + return (method.getLocalVariable(_pc, _index)); + } + + public String getSimpleName() { + return (method.getName()); + } + + /* + * @return the fully qualified name such as "com_amd_javalabs_opencl_demo_PaternityTest$SimpleKernel__actuallyDoIt" + */ + public String getName() { + return (method.getClassModel().getMethod(method.getName(), method.getDescriptor()).getClassModel().getClassWeAreModelling() + .getName().replace('.', '_') + + "__" + method.getName()); + } + + public String getReturnType() { + final String returnType = method.getDescriptorUTF8Entry().getUTF8(); + final int index = returnType.indexOf(")"); + return (returnType.substring(index + 1)); + } + + public List<MethodCall> getMethodCalls() { + final List<MethodCall> methodCalls = new ArrayList<MethodCall>(); + + for (Instruction i = getPCHead(); i != null; i = i.getNextPC()) { + if (i instanceof MethodCall) { + final MethodCall methodCall = (MethodCall) i; + methodCalls.add(methodCall); + } + } + return (methodCalls); + } + + public Instruction getPCHead() { + return (pcHead); + } + + public Instruction getExprHead() { + return (expressionList.getHead()); + } + + @Override public String toString() { + return "MethodModel of " + method; + } +} diff --git a/src/main/java/com/aparapi/internal/model/Supplier.java b/src/main/java/com/aparapi/internal/model/Supplier.java index e72a69605b384741945ac892d8af5e624cb2fc47..8446f2416200bdac3c0bd5d0fc87e125bbd63d60 100644 --- a/src/main/java/com/aparapi/internal/model/Supplier.java +++ b/src/main/java/com/aparapi/internal/model/Supplier.java @@ -1,23 +1,23 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.model; - -/** - * Substitute of Java8's Supplier<V> interface, used in Java7 backport of caches. - */ -public interface Supplier<V> { - V get(); -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.model; + +/** + * Substitute of Java8's Supplier<V> interface, used in Java7 backport of caches. + */ +public interface Supplier<V> { + V get(); +} diff --git a/src/main/java/com/aparapi/internal/model/ValueCache.java b/src/main/java/com/aparapi/internal/model/ValueCache.java index 12bd227b448fd3bb67fb85cff1fdbeefc23456d5..e2568a46d8c7d97ebc95af8cad4195afb62de5c9 100644 --- a/src/main/java/com/aparapi/internal/model/ValueCache.java +++ b/src/main/java/com/aparapi/internal/model/ValueCache.java @@ -1,59 +1,59 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.model; - -import java.lang.ref.*; -import java.util.concurrent.*; - -//import java.util.function.Supplier; - -public final class ValueCache<K, V, T extends Throwable> { - // @FunctionalInterface - public interface ThrowingValueComputer<K, V, T extends Throwable> { - V compute(K key) throws T; - } - - // @FunctionalInterface - public interface ValueComputer<K, V> extends ThrowingValueComputer<K, V, RuntimeException> { - // Marker interface - } - - public static <K, V, T extends Throwable> ValueCache<K, V, T> on(ThrowingValueComputer<K, V, T> computer) { - return new ValueCache<K, V, T>(computer); - } - - private final ConcurrentMap<K, SoftReference<V>> map = new ConcurrentHashMap<>(); - - private final ThrowingValueComputer<K, V, T> computer; - - private ValueCache(ThrowingValueComputer<K, V, T> computer) { - this.computer = computer; - } - - public V computeIfAbsent(K key) throws T { - Reference<V> reference = map.get(key); - V value = reference == null ? null : reference.get(); - if (value == null) { - value = computer.compute(key); - map.put(key, new SoftReference<>(value)); - } - return value; - } - - public void invalidate() { - map.clear(); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.model; + +import java.lang.ref.*; +import java.util.concurrent.*; + +//import java.util.function.Supplier; + +public final class ValueCache<K, V, T extends Throwable> { + // @FunctionalInterface + public interface ThrowingValueComputer<K, V, T extends Throwable> { + V compute(K key) throws T; + } + + // @FunctionalInterface + public interface ValueComputer<K, V> extends ThrowingValueComputer<K, V, RuntimeException> { + // Marker interface + } + + public static <K, V, T extends Throwable> ValueCache<K, V, T> on(ThrowingValueComputer<K, V, T> computer) { + return new ValueCache<K, V, T>(computer); + } + + private final ConcurrentMap<K, SoftReference<V>> map = new ConcurrentHashMap<>(); + + private final ThrowingValueComputer<K, V, T> computer; + + private ValueCache(ThrowingValueComputer<K, V, T> computer) { + this.computer = computer; + } + + public V computeIfAbsent(K key) throws T { + Reference<V> reference = map.get(key); + V value = reference == null ? null : reference.get(); + if (value == null) { + value = computer.compute(key); + map.put(key, new SoftReference<>(value)); + } + return value; + } + + public void invalidate() { + map.clear(); + } +} diff --git a/src/main/java/com/aparapi/internal/opencl/OpenCLArgDescriptor.java b/src/main/java/com/aparapi/internal/opencl/OpenCLArgDescriptor.java index d1fda9fc2de2a5790e056c1fa0a8797a1b650059..2c3349c93816cc1f693d16bdf7405448db08dd49 100644 --- a/src/main/java/com/aparapi/internal/opencl/OpenCLArgDescriptor.java +++ b/src/main/java/com/aparapi/internal/opencl/OpenCLArgDescriptor.java @@ -1,117 +1,117 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * - */ -package com.aparapi.internal.opencl; - -public class OpenCLArgDescriptor{ - - public final static int ARG_BYTE_BIT = 1 << 0x000; - - public final static int ARG_SHORT_BIT = 1 << 0x001; - - public final static int ARG_INT_BIT = 1 << 0x002; - - public final static int ARG_FLOAT_BIT = 1 << 0x003; - - public final static int ARG_LONG_BIT = 1 << 0x004; - - public final static int ARG_DOUBLE_BIT = 1 << 0x005; - - public final static int ARG_ARRAY_BIT = 1 << 0x006; - - public final static int ARG_PRIMITIVE_BIT = 1 << 0x007; - - public final static int ARG_GLOBAL_BIT = 1 << 0x008; - - public final static int ARG_LOCAL_BIT = 1 << 0x009; - - public final static int ARG_CONST_BIT = 1 << 0x00A; - - public final static int ARG_READONLY_BIT = 1 << 0x00B; - - public final static int ARG_WRITEONLY_BIT = 1 << 0x00C; - - public final static int ARG_READWRITE_BIT = 1 << 0x00D; - - public final static int ARG_ISARG_BIT = 1 << 0x00E; - - public OpenCLMem memVal; - - private final String name; - - public long bits; - - public OpenCLKernel kernel; - - - - /** - * Full constructor - * - * @param _name - * @param _bits - */ - public OpenCLArgDescriptor(String _name, long _bits) { - name = _name; - bits = _bits; - } - - @Override public String toString() { - final StringBuilder argBuilder = new StringBuilder(); - - if ((bits & ARG_GLOBAL_BIT) == ARG_GLOBAL_BIT) { - argBuilder.append("__global "); - } else if ((bits & ARG_LOCAL_BIT) == ARG_LOCAL_BIT) { - argBuilder.append("__local "); - } else if ((bits & ARG_CONST_BIT) == ARG_CONST_BIT) { - argBuilder.append("__constant "); - } else if ((bits & ARG_ISARG_BIT) == ARG_ISARG_BIT) { - // - } else { - argBuilder.append("WHATISTHIS?"); - } - - if ((bits & ARG_FLOAT_BIT) == ARG_FLOAT_BIT) { - argBuilder.append("float "); - } else if ((bits & ARG_INT_BIT) == ARG_INT_BIT) { - argBuilder.append("int "); - } else if ((bits & ARG_SHORT_BIT) == ARG_SHORT_BIT) { - argBuilder.append("short "); - } else if ((bits & ARG_DOUBLE_BIT) == ARG_DOUBLE_BIT) { - argBuilder.append("double "); - } else if ((bits & ARG_LONG_BIT) == ARG_LONG_BIT) { - argBuilder.append("long "); - } - - if ((bits & ARG_ARRAY_BIT) == ARG_ARRAY_BIT) { - argBuilder.append("*"); - } - - argBuilder.append(name); - - if ((bits & ARG_READONLY_BIT) == ARG_READONLY_BIT) { - argBuilder.append(" /* readonly */"); - } else if ((bits & ARG_WRITEONLY_BIT) == ARG_WRITEONLY_BIT) { - argBuilder.append(" /* writeonly */"); - } else if ((bits & ARG_READWRITE_BIT) == ARG_READWRITE_BIT) { - argBuilder.append(" /* readwrite */"); - } - - return (argBuilder.toString()); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + */ +package com.aparapi.internal.opencl; + +public class OpenCLArgDescriptor{ + + public final static int ARG_BYTE_BIT = 1 << 0x000; + + public final static int ARG_SHORT_BIT = 1 << 0x001; + + public final static int ARG_INT_BIT = 1 << 0x002; + + public final static int ARG_FLOAT_BIT = 1 << 0x003; + + public final static int ARG_LONG_BIT = 1 << 0x004; + + public final static int ARG_DOUBLE_BIT = 1 << 0x005; + + public final static int ARG_ARRAY_BIT = 1 << 0x006; + + public final static int ARG_PRIMITIVE_BIT = 1 << 0x007; + + public final static int ARG_GLOBAL_BIT = 1 << 0x008; + + public final static int ARG_LOCAL_BIT = 1 << 0x009; + + public final static int ARG_CONST_BIT = 1 << 0x00A; + + public final static int ARG_READONLY_BIT = 1 << 0x00B; + + public final static int ARG_WRITEONLY_BIT = 1 << 0x00C; + + public final static int ARG_READWRITE_BIT = 1 << 0x00D; + + public final static int ARG_ISARG_BIT = 1 << 0x00E; + + public OpenCLMem memVal; + + private final String name; + + public long bits; + + public OpenCLKernel kernel; + + + + /** + * Full constructor + * + * @param _name + * @param _bits + */ + public OpenCLArgDescriptor(String _name, long _bits) { + name = _name; + bits = _bits; + } + + @Override public String toString() { + final StringBuilder argBuilder = new StringBuilder(); + + if ((bits & ARG_GLOBAL_BIT) == ARG_GLOBAL_BIT) { + argBuilder.append("__global "); + } else if ((bits & ARG_LOCAL_BIT) == ARG_LOCAL_BIT) { + argBuilder.append("__local "); + } else if ((bits & ARG_CONST_BIT) == ARG_CONST_BIT) { + argBuilder.append("__constant "); + } else if ((bits & ARG_ISARG_BIT) == ARG_ISARG_BIT) { + // + } else { + argBuilder.append("WHATISTHIS?"); + } + + if ((bits & ARG_FLOAT_BIT) == ARG_FLOAT_BIT) { + argBuilder.append("float "); + } else if ((bits & ARG_INT_BIT) == ARG_INT_BIT) { + argBuilder.append("int "); + } else if ((bits & ARG_SHORT_BIT) == ARG_SHORT_BIT) { + argBuilder.append("short "); + } else if ((bits & ARG_DOUBLE_BIT) == ARG_DOUBLE_BIT) { + argBuilder.append("double "); + } else if ((bits & ARG_LONG_BIT) == ARG_LONG_BIT) { + argBuilder.append("long "); + } + + if ((bits & ARG_ARRAY_BIT) == ARG_ARRAY_BIT) { + argBuilder.append("*"); + } + + argBuilder.append(name); + + if ((bits & ARG_READONLY_BIT) == ARG_READONLY_BIT) { + argBuilder.append(" /* readonly */"); + } else if ((bits & ARG_WRITEONLY_BIT) == ARG_WRITEONLY_BIT) { + argBuilder.append(" /* writeonly */"); + } else if ((bits & ARG_READWRITE_BIT) == ARG_READWRITE_BIT) { + argBuilder.append(" /* readwrite */"); + } + + return (argBuilder.toString()); + } +} diff --git a/src/main/java/com/aparapi/internal/opencl/OpenCLKernel.java b/src/main/java/com/aparapi/internal/opencl/OpenCLKernel.java index 10ce52eaf439bb943f429a96c5f4db7f6d2db500..3b1bba49f4d466e17199b058661e9f5443f4bc0b 100644 --- a/src/main/java/com/aparapi/internal/opencl/OpenCLKernel.java +++ b/src/main/java/com/aparapi/internal/opencl/OpenCLKernel.java @@ -1,80 +1,80 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.opencl; - -import java.util.List; - -import com.aparapi.internal.jni.OpenCLJNI; - -public class OpenCLKernel extends OpenCLJNI{ - - private OpenCLArgDescriptor[] args = null; - - private OpenCLProgram program = null; - - private String kernelName = null; - - private long kernelId = 0; - - /** - * This constructor is specifically for JNI usage - * - * @param kernel - * @param programInstance - * @param name - * @param _args - */ - public OpenCLKernel(long kernel, OpenCLProgram programInstance, String name, OpenCLArgDescriptor[] _args) { - kernelId = kernel; - program = programInstance; - kernelName = name; - args = _args; - } - - private OpenCLKernel() { - } - - /** - * This method is used to create a new Kernel from JNI - * - * @param _program - * @param _kernelName - * @param _args - * @return - */ - public static OpenCLKernel createKernel(OpenCLProgram _program, String _kernelName, List<OpenCLArgDescriptor> _args) { - final OpenCLArgDescriptor[] argArray = _args.toArray(new OpenCLArgDescriptor[0]); - final OpenCLKernel oclk = new OpenCLKernel().createKernelJNI(_program, _kernelName, argArray); - for (final OpenCLArgDescriptor arg : argArray) { - arg.kernel = oclk; - } - return oclk; - } - - public String getName() { - return kernelName; - } - - public void invoke(Object[] _args) { - invoke(this, _args); - } - - public void dispose(){ - disposeKernel(this); - } - - -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.opencl; + +import java.util.List; + +import com.aparapi.internal.jni.OpenCLJNI; + +public class OpenCLKernel extends OpenCLJNI{ + + private OpenCLArgDescriptor[] args = null; + + private OpenCLProgram program = null; + + private String kernelName = null; + + private long kernelId = 0; + + /** + * This constructor is specifically for JNI usage + * + * @param kernel + * @param programInstance + * @param name + * @param _args + */ + public OpenCLKernel(long kernel, OpenCLProgram programInstance, String name, OpenCLArgDescriptor[] _args) { + kernelId = kernel; + program = programInstance; + kernelName = name; + args = _args; + } + + private OpenCLKernel() { + } + + /** + * This method is used to create a new Kernel from JNI + * + * @param _program + * @param _kernelName + * @param _args + * @return + */ + public static OpenCLKernel createKernel(OpenCLProgram _program, String _kernelName, List<OpenCLArgDescriptor> _args) { + final OpenCLArgDescriptor[] argArray = _args.toArray(new OpenCLArgDescriptor[0]); + final OpenCLKernel oclk = new OpenCLKernel().createKernelJNI(_program, _kernelName, argArray); + for (final OpenCLArgDescriptor arg : argArray) { + arg.kernel = oclk; + } + return oclk; + } + + public String getName() { + return kernelName; + } + + public void invoke(Object[] _args) { + invoke(this, _args); + } + + public void dispose(){ + disposeKernel(this); + } + + +} diff --git a/src/main/java/com/aparapi/internal/opencl/OpenCLLoader.java b/src/main/java/com/aparapi/internal/opencl/OpenCLLoader.java index 63bfa6b52be43b544c2affbcf50e2c88eab2a384..948530a7a2e14cd861fd6b48ac4e144b7356f672 100644 --- a/src/main/java/com/aparapi/internal/opencl/OpenCLLoader.java +++ b/src/main/java/com/aparapi/internal/opencl/OpenCLLoader.java @@ -1,72 +1,72 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.opencl; - -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.aparapi.Config; -import com.aparapi.internal.jni.OpenCLJNI; -import com.aparapi.natives.NativeLoader; - -/** - * This class is intended to be a singleton which determines if OpenCL is available upon startup of Aparapi - */ -public class OpenCLLoader extends OpenCLJNI{ - - private static final Logger logger = Logger.getLogger(Config.getLoggerName()); - - private static boolean openCLAvailable = false; - - private static final OpenCLLoader instance = new OpenCLLoader(); - - static { - if (Config.useAgent) { - logger.fine("Using agent!"); - openCLAvailable = true; - } else { - try { - NativeLoader.load(); - logger.info("Aparapi JNI loaded successfully."); - openCLAvailable = true; - } - catch (final IOException e) { - logger.log(Level.SEVERE, "Check your environment. Failed to load aparapi native library " - + " or possibly failed to locate opencl native library (opencl.dll/opencl.so)." - + " Ensure that OpenCL is in your PATH (windows) or in LD_LIBRARY_PATH (linux)."); - } - } - } - - /** - * Retrieve a singleton instance of OpenCLLoader - * - * @return A singleton instance of OpenCLLoader - */ - protected static OpenCLLoader getInstance() { - return instance; - } - - /** - * Retrieve the status of whether OpenCL was successfully loaded - * - * @return The status of whether OpenCL was successfully loaded - */ - public static boolean isOpenCLAvailable() { - return openCLAvailable; - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.opencl; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.aparapi.Config; +import com.aparapi.internal.jni.OpenCLJNI; +import com.aparapi.natives.NativeLoader; + +/** + * This class is intended to be a singleton which determines if OpenCL is available upon startup of Aparapi + */ +public class OpenCLLoader extends OpenCLJNI{ + + private static final Logger logger = Logger.getLogger(Config.getLoggerName()); + + private static boolean openCLAvailable = false; + + private static final OpenCLLoader instance = new OpenCLLoader(); + + static { + if (Config.useAgent) { + logger.fine("Using agent!"); + openCLAvailable = true; + } else { + try { + NativeLoader.load(); + logger.info("Aparapi JNI loaded successfully."); + openCLAvailable = true; + } + catch (final IOException e) { + logger.log(Level.SEVERE, "Check your environment. Failed to load aparapi native library " + + " or possibly failed to locate opencl native library (opencl.dll/opencl.so)." + + " Ensure that OpenCL is in your PATH (windows) or in LD_LIBRARY_PATH (linux)."); + } + } + } + + /** + * Retrieve a singleton instance of OpenCLLoader + * + * @return A singleton instance of OpenCLLoader + */ + protected static OpenCLLoader getInstance() { + return instance; + } + + /** + * Retrieve the status of whether OpenCL was successfully loaded + * + * @return The status of whether OpenCL was successfully loaded + */ + public static boolean isOpenCLAvailable() { + return openCLAvailable; + } +} diff --git a/src/main/java/com/aparapi/internal/opencl/OpenCLMem.java b/src/main/java/com/aparapi/internal/opencl/OpenCLMem.java index 3b2fee6dc9cc8e2cddaeef346190a1cc607ac5ab..912281e431382f453ef9adcf2cad443bfa96ca95 100644 --- a/src/main/java/com/aparapi/internal/opencl/OpenCLMem.java +++ b/src/main/java/com/aparapi/internal/opencl/OpenCLMem.java @@ -1,37 +1,37 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.opencl; - -public class OpenCLMem{ - - public final static int MEM_DIRTY_BIT = 1 << 0x00F; - - public final static int MEM_COPY_BIT = 1 << 0x010; - - public final static int MEM_ENQUEUED_BIT = 1 << 0x011; - - public long bits; // dirty, copy, enqueued - - public int sizeInBytes; - - public long memId; - - public long address; - - public Object instance; - - public OpenCLProgram program; -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.opencl; + +public class OpenCLMem{ + + public final static int MEM_DIRTY_BIT = 1 << 0x00F; + + public final static int MEM_COPY_BIT = 1 << 0x010; + + public final static int MEM_ENQUEUED_BIT = 1 << 0x011; + + public long bits; // dirty, copy, enqueued + + public int sizeInBytes; + + public long memId; + + public long address; + + public Object instance; + + public OpenCLProgram program; +} diff --git a/src/main/java/com/aparapi/internal/opencl/OpenCLPlatform.java b/src/main/java/com/aparapi/internal/opencl/OpenCLPlatform.java index ac2b5201182b3e2e7081d5730c8c86ace32b77ba..43f26969f56cc8e4e7e523920723c89730afe3a5 100644 --- a/src/main/java/com/aparapi/internal/opencl/OpenCLPlatform.java +++ b/src/main/java/com/aparapi/internal/opencl/OpenCLPlatform.java @@ -1,110 +1,110 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.opencl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.aparapi.device.OpenCLDevice; -import com.aparapi.internal.jni.OpenCLJNI; - -public class OpenCLPlatform extends OpenCLJNI{ - - private long platformId; - - private final String version; - - private final String vendor; - - private final String name; - - private final List<OpenCLDevice> devices = new ArrayList<OpenCLDevice>(); - - private static List<OpenCLPlatform> platforms; - - /** - * Default constructor - */ - public OpenCLPlatform() { - version = ""; - vendor = ""; - name = ""; - } - - /** - * Full constructor - * - * @param _platformId - * @param _version - * @param _vendor - * @param _name - */ - public OpenCLPlatform(long _platformId, String _version, String _vendor, String _name) { - platformId = _platformId; - version = _version; - vendor = _vendor; - name = _name; - } - - public void addOpenCLDevice(OpenCLDevice device) { - devices.add(device); - } - - public List<OpenCLDevice> getOpenCLDevices() { - return (devices); - } - - public List<OpenCLPlatform> getOpenCLPlatforms() { - if (platforms == null) { - if (OpenCLLoader.isOpenCLAvailable()) { - platforms = getPlatforms(); - } else { - return (Collections.EMPTY_LIST); - } - } - return platforms; - } - - public static List<OpenCLPlatform> getUncachedOpenCLPlatforms(){ - platforms = null; - platforms = new OpenCLPlatform().getOpenCLPlatforms(); - return platforms; - } - - public String getName() { - return (name); - } - - public String getVersion() { - return (version); - } - - public String getVendor() { - return (vendor); - } - - @Override public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("PlatformId "); - sb.append("\nName:"); - sb.append(vendor); - sb.append("\nVersion:"); - sb.append(version); - - return sb.toString(); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.opencl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.aparapi.device.OpenCLDevice; +import com.aparapi.internal.jni.OpenCLJNI; + +public class OpenCLPlatform extends OpenCLJNI{ + + private long platformId; + + private final String version; + + private final String vendor; + + private final String name; + + private final List<OpenCLDevice> devices = new ArrayList<OpenCLDevice>(); + + private static List<OpenCLPlatform> platforms; + + /** + * Default constructor + */ + public OpenCLPlatform() { + version = ""; + vendor = ""; + name = ""; + } + + /** + * Full constructor + * + * @param _platformId + * @param _version + * @param _vendor + * @param _name + */ + public OpenCLPlatform(long _platformId, String _version, String _vendor, String _name) { + platformId = _platformId; + version = _version; + vendor = _vendor; + name = _name; + } + + public void addOpenCLDevice(OpenCLDevice device) { + devices.add(device); + } + + public List<OpenCLDevice> getOpenCLDevices() { + return (devices); + } + + public List<OpenCLPlatform> getOpenCLPlatforms() { + if (platforms == null) { + if (OpenCLLoader.isOpenCLAvailable()) { + platforms = getPlatforms(); + } else { + return (Collections.EMPTY_LIST); + } + } + return platforms; + } + + public static List<OpenCLPlatform> getUncachedOpenCLPlatforms(){ + platforms = null; + platforms = new OpenCLPlatform().getOpenCLPlatforms(); + return platforms; + } + + public String getName() { + return (name); + } + + public String getVersion() { + return (version); + } + + public String getVendor() { + return (vendor); + } + + @Override public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("PlatformId "); + sb.append("\nName:"); + sb.append(vendor); + sb.append("\nVersion:"); + sb.append(version); + + return sb.toString(); + } +} diff --git a/src/main/java/com/aparapi/internal/opencl/OpenCLProgram.java b/src/main/java/com/aparapi/internal/opencl/OpenCLProgram.java index dfd417f83869dd534b945197d7675c1c4e1c38c5..1f01246ca1721e4442439fd1cfcc88cd9fa6b6cf 100644 --- a/src/main/java/com/aparapi/internal/opencl/OpenCLProgram.java +++ b/src/main/java/com/aparapi/internal/opencl/OpenCLProgram.java @@ -1,114 +1,114 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.opencl; - -import com.aparapi.ProfileInfo; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.aparapi.device.OpenCLDevice; -import com.aparapi.internal.jni.OpenCLJNI; - -public class OpenCLProgram extends OpenCLJNI{ - - private final long programId; - - private final long queueId; - - private final long contextId; - - private final long profileInfo = 0L; - - private final OpenCLDevice device; - - private final String source; - - /** - * FIXME Why are these not ConcurrentHashMaps or at least synchronized at a finer grain? - */ - private final Map<Object, OpenCLMem> instanceToMem = new HashMap<Object, OpenCLMem>(); - - private final Map<Long, OpenCLMem> addressToMem = new HashMap<Long, OpenCLMem>(); - - /** - * Minimal constructor - */ - public OpenCLProgram(OpenCLDevice _device, String _source) { - programId = 0; - queueId = 0; - contextId = 0; - device = _device; - source = _source; - } - - /** - * Full constructor - * - * @param _programId - * @param _queueId - * @param _contextId - * @param _device - * @param _source - */ - public OpenCLProgram(long _programId, long _queueId, long _contextId, OpenCLDevice _device, String _source) { - programId = _programId; - queueId = _queueId; - contextId = _contextId; - device = _device; - source = _source; - } - - public OpenCLProgram createProgram(OpenCLDevice context) { - return createProgram(context, source); - } - - public OpenCLDevice getDevice() { - return device; - } - - public synchronized OpenCLMem getMem(Object _instance, long _address) { - OpenCLMem mem = instanceToMem.get(_instance); - - if (mem == null) { - mem = addressToMem.get(_instance); - if (mem != null) { - System.out.println("object has been moved, we need to remap the buffer"); - remap(this, mem, _address); - } - } - - return (mem); - } - - public synchronized void add(Object _instance, long _address, OpenCLMem _mem) { - instanceToMem.put(_instance, _mem); - addressToMem.put(_address, _mem); - } - - public synchronized void remapped(Object _instance, long _address, OpenCLMem _mem, long _oldAddress) { - addressToMem.remove(_oldAddress); - addressToMem.put(_address, _mem); - } - - public void dispose(){ - disposeProgram(this); - } - - public List<ProfileInfo> getProfileInfo(){ - return(getProfileInfo(this)); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.opencl; + +import com.aparapi.ProfileInfo; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.aparapi.device.OpenCLDevice; +import com.aparapi.internal.jni.OpenCLJNI; + +public class OpenCLProgram extends OpenCLJNI{ + + private final long programId; + + private final long queueId; + + private final long contextId; + + private final long profileInfo = 0L; + + private final OpenCLDevice device; + + private final String source; + + /** + * FIXME Why are these not ConcurrentHashMaps or at least synchronized at a finer grain? + */ + private final Map<Object, OpenCLMem> instanceToMem = new HashMap<Object, OpenCLMem>(); + + private final Map<Long, OpenCLMem> addressToMem = new HashMap<Long, OpenCLMem>(); + + /** + * Minimal constructor + */ + public OpenCLProgram(OpenCLDevice _device, String _source) { + programId = 0; + queueId = 0; + contextId = 0; + device = _device; + source = _source; + } + + /** + * Full constructor + * + * @param _programId + * @param _queueId + * @param _contextId + * @param _device + * @param _source + */ + public OpenCLProgram(long _programId, long _queueId, long _contextId, OpenCLDevice _device, String _source) { + programId = _programId; + queueId = _queueId; + contextId = _contextId; + device = _device; + source = _source; + } + + public OpenCLProgram createProgram(OpenCLDevice context) { + return createProgram(context, source); + } + + public OpenCLDevice getDevice() { + return device; + } + + public synchronized OpenCLMem getMem(Object _instance, long _address) { + OpenCLMem mem = instanceToMem.get(_instance); + + if (mem == null) { + mem = addressToMem.get(_instance); + if (mem != null) { + System.out.println("object has been moved, we need to remap the buffer"); + remap(this, mem, _address); + } + } + + return (mem); + } + + public synchronized void add(Object _instance, long _address, OpenCLMem _mem) { + instanceToMem.put(_instance, _mem); + addressToMem.put(_address, _mem); + } + + public synchronized void remapped(Object _instance, long _address, OpenCLMem _mem, long _oldAddress) { + addressToMem.remove(_oldAddress); + addressToMem.put(_address, _mem); + } + + public void dispose(){ + disposeProgram(this); + } + + public List<ProfileInfo> getProfileInfo(){ + return(getProfileInfo(this)); + } +} diff --git a/src/main/java/com/aparapi/internal/reader/ByteBuffer.java b/src/main/java/com/aparapi/internal/reader/ByteBuffer.java index 583e05196db03db514ec7883051b2a11d6b732ae..a5dbb43f27c5d12ec74cf96b51a56d0c86b1616f 100644 --- a/src/main/java/com/aparapi/internal/reader/ByteBuffer.java +++ b/src/main/java/com/aparapi/internal/reader/ByteBuffer.java @@ -1,240 +1,240 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.reader; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Used to parse ClassFile structure. <br/> - * - * Provides low level access to sequential bytes in a stream given a specific offset. - * - * Does not keep track of accesses. For this you will need a <code>ByteReader</code> - * - * @see com.aparapi.internal.reader.ByteReader - * - * @author gfrost - * - */ -public class ByteBuffer{ - - private byte[] bytes; - - /** - * Construct from an <code>InputStream</code> - * - * @param _inputStream - */ - ByteBuffer(InputStream _inputStream) { - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - bytes = new byte[4096]; - int bytesRead = 0; - - try { - while ((bytesRead = _inputStream.read(bytes)) > 0) { - baos.write(bytes, 0, bytesRead); - } - - bytes = baos.toByteArray(); - } catch (final IOException e) { - bytes = new byte[0]; - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - int u2(int _offset) { - return ((u1(_offset) << 8) | u1(_offset + 1)); - } - - int s2(int _offset) { - int s2 = u2(_offset); - - if (s2 > 0x7fff) { - s2 = -(0x10000 - s2); - } - return (s2); - } - - int u4(int _offset) { - return (((u2(_offset) & 0xffff) << 16) | u2(_offset + 2)); - } - - int s4(int _offset) { - final int s4 = u4(_offset); - return (s4); - } - - ByteBuffer(byte[] _bytes) { - bytes = _bytes; - } - - int u1(int _offset) { - return ((bytes[_offset] & 0xff)); - } - - int size() { - return (bytes.length); - } - - double d8(int _offset) { - return (Double.longBitsToDouble(u8(_offset))); - } - - float f4(int _offset) { - return (Float.intBitsToFloat(u4(_offset))); - - } - - long u8(int _offset) { - return ((u4(_offset) & 0xffffffffL) << 32) | (u4(_offset + 4) & 0xffffffffL); - } - - int utf8bytes(int _offset) { - return (2 + u2(_offset)); - } - - byte[] bytes(int _offset, int _length) { - final byte[] returnBytes = new byte[_length]; - System.arraycopy(bytes, _offset, returnBytes, 0, _length); - return (returnBytes); - } - - String utf8(int _offset) { - final int utflen = u2(_offset); - _offset += 2; - final byte[] bytearr = new byte[utflen]; - final char[] chararr = new char[utflen]; - - int c, char2, char3; - int count = 0; - int chararr_count = 0; - - for (int i = 0; i < utflen; i++) { - bytearr[i] = b(_offset + i); - } - _offset += utflen; - - while (count < utflen) { - c = bytearr[count] & 0xff; - if (c > 127) { - break; - } - count++; - chararr[chararr_count++] = (char) c; - } - - while (count < utflen) { - c = bytearr[count] & 0xff; - switch (c >> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - /* 0xxxxxxx*/ - count++; - chararr[chararr_count++] = (char) c; - break; - case 12: - case 13: - /* 110x xxxx 10xx xxxx*/ - count += 2; - if (count > utflen) { - System.out.println("malformed input: partial character at end"); - return (null); - } - char2 = bytearr[count - 1]; - if ((char2 & 0xC0) != 0x80) { - System.out.println("malformed input around byte " + count); - return (null); - } - chararr[chararr_count++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); - break; - case 14: - /* 1110 xxxx 10xx xxxx 10xx xxxx */ - count += 3; - if (count > utflen) { - System.out.println("malformed input: partial character at end"); - return (null); - } - char2 = bytearr[count - 2]; - char3 = bytearr[count - 1]; - if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { - System.out.println("malformed input around byte " + (count - 1)); - return (null); - } - chararr[chararr_count++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); - break; - default: - /* 10xx xxxx, 1111 xxxx */ - System.out.println("malformed input around byte " + count); - return (null); - } - } - // The number of chars produced may be less than utflen - final String returnString = new String(chararr, 0, chararr_count); - // System.out.println("returnString.length="+returnString.length()+" byte[]="+bytearr.length); - return (returnString); - } - - byte b(int _offset) { - return bytes[_offset]; - } - -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.reader; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Used to parse ClassFile structure. <br/> + * + * Provides low level access to sequential bytes in a stream given a specific offset. + * + * Does not keep track of accesses. For this you will need a <code>ByteReader</code> + * + * @see com.aparapi.internal.reader.ByteReader + * + * @author gfrost + * + */ +public class ByteBuffer{ + + private byte[] bytes; + + /** + * Construct from an <code>InputStream</code> + * + * @param _inputStream + */ + ByteBuffer(InputStream _inputStream) { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bytes = new byte[4096]; + int bytesRead = 0; + + try { + while ((bytesRead = _inputStream.read(bytes)) > 0) { + baos.write(bytes, 0, bytesRead); + } + + bytes = baos.toByteArray(); + } catch (final IOException e) { + bytes = new byte[0]; + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + int u2(int _offset) { + return ((u1(_offset) << 8) | u1(_offset + 1)); + } + + int s2(int _offset) { + int s2 = u2(_offset); + + if (s2 > 0x7fff) { + s2 = -(0x10000 - s2); + } + return (s2); + } + + int u4(int _offset) { + return (((u2(_offset) & 0xffff) << 16) | u2(_offset + 2)); + } + + int s4(int _offset) { + final int s4 = u4(_offset); + return (s4); + } + + ByteBuffer(byte[] _bytes) { + bytes = _bytes; + } + + int u1(int _offset) { + return ((bytes[_offset] & 0xff)); + } + + int size() { + return (bytes.length); + } + + double d8(int _offset) { + return (Double.longBitsToDouble(u8(_offset))); + } + + float f4(int _offset) { + return (Float.intBitsToFloat(u4(_offset))); + + } + + long u8(int _offset) { + return ((u4(_offset) & 0xffffffffL) << 32) | (u4(_offset + 4) & 0xffffffffL); + } + + int utf8bytes(int _offset) { + return (2 + u2(_offset)); + } + + byte[] bytes(int _offset, int _length) { + final byte[] returnBytes = new byte[_length]; + System.arraycopy(bytes, _offset, returnBytes, 0, _length); + return (returnBytes); + } + + String utf8(int _offset) { + final int utflen = u2(_offset); + _offset += 2; + final byte[] bytearr = new byte[utflen]; + final char[] chararr = new char[utflen]; + + int c, char2, char3; + int count = 0; + int chararr_count = 0; + + for (int i = 0; i < utflen; i++) { + bytearr[i] = b(_offset + i); + } + _offset += utflen; + + while (count < utflen) { + c = bytearr[count] & 0xff; + if (c > 127) { + break; + } + count++; + chararr[chararr_count++] = (char) c; + } + + while (count < utflen) { + c = bytearr[count] & 0xff; + switch (c >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + /* 0xxxxxxx*/ + count++; + chararr[chararr_count++] = (char) c; + break; + case 12: + case 13: + /* 110x xxxx 10xx xxxx*/ + count += 2; + if (count > utflen) { + System.out.println("malformed input: partial character at end"); + return (null); + } + char2 = bytearr[count - 1]; + if ((char2 & 0xC0) != 0x80) { + System.out.println("malformed input around byte " + count); + return (null); + } + chararr[chararr_count++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); + break; + case 14: + /* 1110 xxxx 10xx xxxx 10xx xxxx */ + count += 3; + if (count > utflen) { + System.out.println("malformed input: partial character at end"); + return (null); + } + char2 = bytearr[count - 2]; + char3 = bytearr[count - 1]; + if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { + System.out.println("malformed input around byte " + (count - 1)); + return (null); + } + chararr[chararr_count++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); + break; + default: + /* 10xx xxxx, 1111 xxxx */ + System.out.println("malformed input around byte " + count); + return (null); + } + } + // The number of chars produced may be less than utflen + final String returnString = new String(chararr, 0, chararr_count); + // System.out.println("returnString.length="+returnString.length()+" byte[]="+bytearr.length); + return (returnString); + } + + byte b(int _offset) { + return bytes[_offset]; + } + +} diff --git a/src/main/java/com/aparapi/internal/reader/ByteReader.java b/src/main/java/com/aparapi/internal/reader/ByteReader.java index da507b812334bbf587c7b03c48d38e5ffa932aae..a40167a0b0299220d3f2c0fc1bed79df29b0c26e 100644 --- a/src/main/java/com/aparapi/internal/reader/ByteReader.java +++ b/src/main/java/com/aparapi/internal/reader/ByteReader.java @@ -1,180 +1,180 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.reader; - -import java.io.InputStream; - -/** - * Primarily used to parse various ClassFile structures. This class provides low level access to sequential bytes in a stream given stream. - * <p> - * Basically wraps a <code>ByteBuffer</code> and keeps track of the current offset. All requests on - * this <code>ByteReader</code> will be delegated to wrapped<code>ByteBuffer</code>. - * </p> - * @see com.aparapi.internal.reader.ByteBuffer - * - * @author gfrost - * - */ -public class ByteReader{ - - private final ByteBuffer byteBuffer; - - private int offset; - - /** - * Construct form a given ByteBuffer. - * - * @param _byteBuffer an existing <code>ByteBuffer</code> - */ - public ByteReader(ByteBuffer _byteBuffer) { - byteBuffer = _byteBuffer; - } - - /** - * Construct form an array of bytes. - * - * @param _bytes an existing byte array - */ - public ByteReader(byte[] _bytes) { - this(new ByteBuffer(_bytes)); - } - - /** - * Construct form an input stream (say a ClassFile). - * - * @param _inputStream a stream of bytes - */ - public ByteReader(InputStream _inputStream) { - this(new ByteBuffer(_inputStream)); - } - - public int u1() { - final int value = byteBuffer.u1(offset); - offset += 1; - return (value); - } - - public int u2() { - final int value = byteBuffer.u2(offset); - offset += 2; - return (value); - } - - public int s2() { - final int value = byteBuffer.s2(offset); - offset += 2; - return (value); - } - - public int peekU2() { - return (byteBuffer.u2(offset)); - } - - public int u4() { - final int value = byteBuffer.u4(offset); - offset += 4; - return (value); - } - - public int s4() { - final int value = byteBuffer.s4(offset); - offset += 4; - return (value); - } - - public long u8() { - final long value = byteBuffer.u8(offset); - offset += 8; - return (value); - } - - public float f4() { - final float value = byteBuffer.f4(offset); - offset += 4; - return (value); - } - - public double d8() { - final double value = byteBuffer.d8(offset); - offset += 8; - return (value); - } - - public String utf8() { - final String utf8 = byteBuffer.utf8(offset); - offset += byteBuffer.utf8bytes(offset); - return (utf8); - } - - public byte[] bytes(int _length) { - final byte[] bytes = byteBuffer.bytes(offset, _length); - offset += _length; - return (bytes); - } - - public void skip(int _length) { - offset += _length; - } - - public int getOffset() { - return (offset); - } - - public void setOffset(int _offset) { - offset = _offset; - } - - public boolean hasMore() { - return (getOffset() < byteBuffer.size()); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.reader; + +import java.io.InputStream; + +/** + * Primarily used to parse various ClassFile structures. This class provides low level access to sequential bytes in a stream given stream. + * <p> + * Basically wraps a <code>ByteBuffer</code> and keeps track of the current offset. All requests on + * this <code>ByteReader</code> will be delegated to wrapped<code>ByteBuffer</code>. + * </p> + * @see com.aparapi.internal.reader.ByteBuffer + * + * @author gfrost + * + */ +public class ByteReader{ + + private final ByteBuffer byteBuffer; + + private int offset; + + /** + * Construct form a given ByteBuffer. + * + * @param _byteBuffer an existing <code>ByteBuffer</code> + */ + public ByteReader(ByteBuffer _byteBuffer) { + byteBuffer = _byteBuffer; + } + + /** + * Construct form an array of bytes. + * + * @param _bytes an existing byte array + */ + public ByteReader(byte[] _bytes) { + this(new ByteBuffer(_bytes)); + } + + /** + * Construct form an input stream (say a ClassFile). + * + * @param _inputStream a stream of bytes + */ + public ByteReader(InputStream _inputStream) { + this(new ByteBuffer(_inputStream)); + } + + public int u1() { + final int value = byteBuffer.u1(offset); + offset += 1; + return (value); + } + + public int u2() { + final int value = byteBuffer.u2(offset); + offset += 2; + return (value); + } + + public int s2() { + final int value = byteBuffer.s2(offset); + offset += 2; + return (value); + } + + public int peekU2() { + return (byteBuffer.u2(offset)); + } + + public int u4() { + final int value = byteBuffer.u4(offset); + offset += 4; + return (value); + } + + public int s4() { + final int value = byteBuffer.s4(offset); + offset += 4; + return (value); + } + + public long u8() { + final long value = byteBuffer.u8(offset); + offset += 8; + return (value); + } + + public float f4() { + final float value = byteBuffer.f4(offset); + offset += 4; + return (value); + } + + public double d8() { + final double value = byteBuffer.d8(offset); + offset += 8; + return (value); + } + + public String utf8() { + final String utf8 = byteBuffer.utf8(offset); + offset += byteBuffer.utf8bytes(offset); + return (utf8); + } + + public byte[] bytes(int _length) { + final byte[] bytes = byteBuffer.bytes(offset, _length); + offset += _length; + return (bytes); + } + + public void skip(int _length) { + offset += _length; + } + + public int getOffset() { + return (offset); + } + + public void setOffset(int _offset) { + offset = _offset; + } + + public boolean hasMore() { + return (getOffset() < byteBuffer.size()); + } +} diff --git a/src/main/java/com/aparapi/internal/tool/InstructionHelper.java b/src/main/java/com/aparapi/internal/tool/InstructionHelper.java index 243d644d377d56fac61e5662cd39a7267e543f0c..aedcd6cb3b4be96c447705dfbef71cddb1045b2f 100644 --- a/src/main/java/com/aparapi/internal/tool/InstructionHelper.java +++ b/src/main/java/com/aparapi/internal/tool/InstructionHelper.java @@ -1,607 +1,607 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.tool; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import com.aparapi.internal.exception.CodeGenException; -import com.aparapi.internal.instruction.Instruction; -import com.aparapi.internal.instruction.InstructionSet.AssignToLocalVariable; -import com.aparapi.internal.instruction.InstructionSet.Branch; -import com.aparapi.internal.instruction.InstructionSet.ByteCode; -import com.aparapi.internal.instruction.InstructionSet.CloneInstruction; -import com.aparapi.internal.instruction.InstructionSet.CompositeInstruction; -import com.aparapi.internal.instruction.InstructionSet.ConditionalBranch16; -import com.aparapi.internal.instruction.InstructionSet.Constant; -import com.aparapi.internal.instruction.InstructionSet.FieldReference; -import com.aparapi.internal.instruction.InstructionSet.I_ACONST_NULL; -import com.aparapi.internal.instruction.InstructionSet.I_IINC; -import com.aparapi.internal.instruction.InstructionSet.LocalVariableTableIndexAccessor; -import com.aparapi.internal.instruction.InstructionSet.MethodCall; -import com.aparapi.internal.instruction.InstructionSet.OperatorInstruction; -import com.aparapi.internal.model.ClassModel; -import com.aparapi.internal.model.Entrypoint; -import com.aparapi.internal.model.MethodModel; -import com.aparapi.internal.model.ClassModel.LocalVariableInfo; -import com.aparapi.internal.writer.BlockWriter; - -public class InstructionHelper{ - - public static class Table{ - - final static String spaces = " "; - - private final List<Table.Col> cols = new ArrayList<Table.Col>(); - - private int size = 0; - - private int col = 0; - - public static class Col{ - private final List<String> text = new ArrayList<String>(); - - private int width; - - private String format = "%s"; - - public Col(String _format) { - format = _format; - } - - public Col() { - this("%s"); - } - - public void format(Object... args) { - final String s = String.format(format, args); - - width = Math.max(s.length(), width); - text.add(s); - } - - public int size() { - return (text.size()); - } - - public String pad(String _s, int _width) { - final int length = _s.length(); - final int padWidth = _width - length; - final String padded = _s + spaces.substring(0, padWidth); - return (padded); - - } - - public String get(int _i) { - - return (pad(text.get(_i), width)); - } - - public void header(String _header) { - text.add(_header); - width = _header.length(); - } - } - - public Table(String... _formats) { - for (final String format : _formats) { - cols.add(new Col(format)); - } - } - - public void data(Object... args) { - cols.get(col++).format(args); - if (col == cols.size()) { - col = 0; - size++; - } - } - - @Override public String toString() { - final StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < size; i++) { - for (final Table.Col col : cols) { - sb.append(col.get(i)); - } - sb.append("\n"); - } - - return (sb.toString()); - } - - public void header(String... _headers) { - for (int i = 0; i < _headers.length; i++) { - cols.get(i).header(_headers[i]); - } - - size++; - } - } - - public static class StringWriter extends BlockWriter{ - private StringBuilder sb = null; - - public StringWriter(StringBuilder _sb) { - sb = _sb; - } - - public StringWriter() { - sb = new StringBuilder(); - } - - @Override public void write(String _string) { - sb.append(_string); - } - - @Override public String toString() { - return (sb.toString().trim()); - } - - public void clear() { - sb = new StringBuilder(); - } - - public static String write(MethodModel _methodModel) throws CodeGenException { - final StringWriter sw = new StringWriter(); - sw.writeMethodBody(_methodModel); - return (sw.toString()); - } - - @Override public void write(Entrypoint entryPoint) { - // TODO Auto-generated method stub - } - - @Override public void writeMethodBody(MethodModel _methodModel) throws CodeGenException { - super.writeMethodBody(_methodModel); - } - } - - public static class BranchVector{ - protected Instruction from; - - protected Instruction to; - - protected Instruction start; - - protected Instruction end; - - private boolean forward = false; - - public BranchVector(Instruction _from, Instruction _to) { - from = _from; - to = _to; - if (from.getThisPC() > to.getThisPC()) { - start = _to; - end = _from; - forward = false; - } else { - start = _from; - end = _to; - forward = true; - } - - } - - public boolean overlaps(BranchVector _other) { - final boolean overlap = ((start.getThisPC() < _other.start.getThisPC()) && (end.getThisPC() > _other.start.getThisPC()) && (end - .getThisPC() <= _other.end.getThisPC())) // - || ((_other.start.getThisPC() < start.getThisPC()) && (_other.start.getThisPC() > start.getThisPC()) && (_other.end - .getThisPC() <= end.getThisPC())); - - return (overlap); - } - - public Instruction getTo() { - return (to); - } - - public Instruction getFrom() { - return (from); - } - - public int getStartPC() { - return (start.getThisPC()); - } - - public int getEndPC() { - return (end.getThisPC()); - } - - public Instruction getStart() { - return (start); - } - - public Instruction getEnd() { - return (end); - } - - @Override public boolean equals(Object other) { - return ((other instanceof BranchVector) && ((other == this) || (((BranchVector) other).from - .equals(((BranchVector) other).to)))); - } - - @Override public int hashCode() { - return ((from.hashCode() * 31) + to.hashCode()); - - } - - public boolean isForward() { - return (forward); - } - - @Override public String toString() { - if (isForward()) { - return ("forward from " + getStart() + " to " + getEnd()); - } - return ("backward from " + getEnd() + " to " + getStart()); - } - - public boolean isConditionalBranch() { - return (getFrom().isBranch() && getFrom().asBranch().isConditional()); - } - - public boolean isBackward() { - return (!isForward()); - } - - public static final String NONE = " "; - - public static final String THROUGH = "|"; - - public static final String CONDITIONAL_START = "?"; - - public static final String UNCONDITIONAL_START = "-"; - - public static final String TOP_ARROW = "^"; - - public static final String BOTTOM_ARROW = "v"; - - public String render(int _pc) { - String returnString = NONE; - - if (isForward()) { - if (_pc == getStartPC()) { - returnString = isConditionalBranch() ? CONDITIONAL_START : UNCONDITIONAL_START; - } else if ((_pc > getStartPC()) && (_pc < getEndPC())) { - returnString = THROUGH; - } else if (_pc == getEndPC()) { - returnString = BOTTOM_ARROW; - } - } else { - if (_pc == getStartPC()) { - returnString = TOP_ARROW; - } else if ((_pc > getStartPC()) && (_pc < getEndPC())) { - returnString = THROUGH; - } else if (_pc == getEndPC()) { - returnString = isConditionalBranch() ? CONDITIONAL_START : UNCONDITIONAL_START; - } - } - return returnString; - } - - public String render(int _startPC, int _thisPC) { - String returnString = NONE; - if (isForward()) { - if (_startPC == getStartPC()) { - returnString = isConditionalBranch() ? CONDITIONAL_START : UNCONDITIONAL_START; - } else if ((_thisPC > getStartPC()) && (_startPC < getEndPC())) { - returnString = THROUGH; - } else if (_thisPC == getEndPC()) { - returnString = BOTTOM_ARROW; - } - } else { - if (_startPC == getStartPC()) { - returnString = TOP_ARROW; - } else if ((_thisPC > getStartPC()) && (_startPC < getEndPC())) { - returnString = THROUGH; - } else if (_thisPC == getEndPC()) { - returnString = isConditionalBranch() ? CONDITIONAL_START : UNCONDITIONAL_START; - } - } - - return returnString; - } - } - - public static String getLabel(Instruction instruction, boolean showNumber, boolean showExpressions, boolean verboseBytecodeLabels) { - - final ByteCode byteCode = instruction.getByteCode(); - final StringBuilder label = new StringBuilder(); - if (showNumber) { - label.append(String.format("%3d: ", instruction.getThisPC())); - } - - if (!showExpressions) { - final String byteCodeName = byteCode.getName(); - - if (!verboseBytecodeLabels) { - label.append(byteCodeName); - } else { - if (instruction instanceof ConditionalBranch16) { - final ConditionalBranch16 conditionalBranch16 = (ConditionalBranch16) instruction; - label.append(conditionalBranch16.getOperator().getText()); - label.append(" -> "); - label.append(conditionalBranch16.getTarget().getThisPC()); - } else if (instruction instanceof Branch) { - final Branch branch = (Branch) instruction; - label.append(" -> "); - label.append(branch.getTarget().getThisPC()); - } else if (instruction instanceof MethodCall) { - final MethodCall methodCall = (MethodCall) instruction; - label.append(methodCall.getConstantPoolMethodEntry().getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); - label.append(" "); - label.append(methodCall.getConstantPoolMethodEntry().getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8()); - } else if (instruction instanceof OperatorInstruction) { - final OperatorInstruction operatorInstruction = (OperatorInstruction) instruction; - label.append(operatorInstruction.getOperator().getText() + "(" + byteCodeName + ")"); - } else if (instruction instanceof FieldReference) { - final FieldReference field = (FieldReference) instruction; - label.append(field.getConstantPoolFieldEntry().getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); - label.append(field.getConstantPoolFieldEntry().getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8()); - } else if (instruction instanceof Constant<?>) { - final Constant<?> constant = (Constant<?>) instruction; - final Object value = constant.getValue(); - if (value != null) { - label.append(value); - } else { - if (instruction instanceof I_ACONST_NULL) { - label.append("null"); - } else { - label.append(byteCodeName); - } - } - } else if (instruction instanceof AssignToLocalVariable) { - - final AssignToLocalVariable assignToLocalVariable = (AssignToLocalVariable) instruction; - final LocalVariableInfo info = assignToLocalVariable.getLocalVariableInfo(); - - if (assignToLocalVariable.isDeclaration()) { - label.append(ClassModel.convert(info.getVariableDescriptor())); - } - - label.append(info == null ? "?" : info.getVariableName()); - label.append("="); - - } else if (instruction instanceof LocalVariableTableIndexAccessor) { - final LocalVariableTableIndexAccessor localVariableAccessor = (LocalVariableTableIndexAccessor) instruction; - final LocalVariableInfo info = localVariableAccessor.getLocalVariableInfo(); - label.append(info.getVariableName()); - - } else if (instruction instanceof I_IINC) { - - label.append(instruction.getByteCode()); - label.append(" " + ((I_IINC) instruction).getDelta()); - label.append(" " + ((I_IINC) instruction).getLocalVariableInfo().getVariableName()); - } else if (instruction instanceof CompositeInstruction) { - label.append("composite "); - label.append(instruction.getByteCode()); - } else { - label.append(byteCodeName); - } - } - } else { - final StringWriter writer = new StringWriter(label); - try { - writer.writeInstruction(instruction); - } catch (final CodeGenException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - writer.write("// exception " + e.getMessage()); - } - } - - return (label.toString()); - } - - private static void appendFoldedInstruction(Table _sl, String _prefix, Instruction _instruction) { - _sl.data(_instruction.getThisPC()); - _sl.data(_prefix + InstructionHelper.getLabel(_instruction, false, false, true)); - final int startPc = _instruction.getStartPC(); - final int thisPc = _instruction.getThisPC(); - - final StringBuilder sb = new StringBuilder(); - for (final BranchVector branchInfo : getBranches(_instruction.getMethod())) { - sb.append(branchInfo.render(startPc, thisPc)); - } - - _sl.data(sb.toString()); - for (Instruction child = _instruction.getFirstChild(); child != null; child = child.getNextExpr()) { - appendFoldedInstruction(_sl, _prefix + " ", child); - } - } - - static void writeExpression(String _prefix, Instruction _instruction) { - System.out.println(_prefix + InstructionHelper.getLabel(_instruction, true, true, false)); - } - - static String getFoldedView(MethodModel _methodModel) { - final Table sl = new Table("%4d", " %s", " %s"); - sl.header(" pc", " expression", " branches"); - for (Instruction root = _methodModel.getExprHead(); root != null; root = root.getNextExpr()) { - appendFoldedInstruction(sl, "", root); - } - return (sl.toString()); - } - - static String createView(MethodModel _methodModel, String _msg, Instruction _head) { - final Table table = new Table("[%2d-%2d] ", "%-60s", "%s"); - for (Instruction root = _head; root != null; root = root.getNextExpr()) { - - final String label = InstructionHelper.getLabel(root, false, true, false); - final StringBuilder sb = new StringBuilder(); - for (final BranchVector branchInfo : getBranches(_methodModel)) { - sb.append(branchInfo.render(root.getThisPC(), root.getStartPC())); - } - table.data(root.getStartPC(), root.getThisPC()); - table.data(label); - table.data(sb); - - } - return (_msg + "{\n" + table.toString() + "}\n"); - } - - static String createView(MethodModel _methodModel, String _msg, Instruction _head, Instruction _tail, - int _pcForwardBranchTargetCounts[]) { - final Table table = new Table("[%2d-%2d] ", "%-40s", "%s", "%3d"); - - for (Instruction root = _head; root != null; root = root.getNextExpr()) { - final String label = InstructionHelper.getLabel(root, false, false, false); - final StringBuilder sb = new StringBuilder(); - for (final BranchVector branchInfo : getBranches(_methodModel)) { - sb.append(branchInfo.render(root.getThisPC(), root.getStartPC())); - } - table.data(root.getStartPC(), root.getThisPC()); - table.data(" " + label); - table.data(sb); - table.data(_pcForwardBranchTargetCounts[root.getStartPC()]); - } - final String label = InstructionHelper.getLabel(_tail, false, false, false); - final StringBuilder sb = new StringBuilder(); - for (final BranchVector branchInfo : getBranches(_methodModel)) { - sb.append(branchInfo.render(_tail.getThisPC(), _tail.getStartPC())); - } - table.data(_tail.getStartPC(), _tail.getThisPC()); - table.data("[" + label + "]"); - table.data(sb); - table.data(_pcForwardBranchTargetCounts[_tail.getStartPC()]); - return (_msg + "{\n" + table.toString() + "}\n"); - } - - static String getJavapView(MethodModel _methodModel) { - final Table table = new Table("%4d", "%4d", " %s", " %s"); - table.header("stack ", "pc ", " mnemonic", " branches"); - int stack = 0; - for (Instruction i = _methodModel.getPCHead(); i != null; i = i.getNextPC()) { - stack += i.getStackDelta(); - final int pc = i.getThisPC(); - table.data(stack); - table.data(pc); - table.data(InstructionHelper.getLabel(i, false, false, false)); - if (true) { - final StringBuilder sb = new StringBuilder(); - for (final BranchVector branchInfo : getBranches(_methodModel)) { - sb.append(branchInfo.render(pc)); - } - table.data(sb); - } - - } - return (table.toString()); - } - - private static Comparator<BranchVector> branchInfoComparator = new Comparator<BranchVector>(){ - @Override public int compare(BranchVector left, BranchVector right) { - final int value = left.getFrom().compareTo(right.getFrom()); - return (value); - } - - }; - - static List<BranchVector> getBranches(MethodModel _methodModel) { - final List<BranchVector> branchVectors = new ArrayList<BranchVector>(); - - for (Instruction instruction = _methodModel.getPCHead(); instruction != null; instruction = instruction.getNextPC()) { - if (instruction.isBranch()) { - final Branch branch = (Branch) instruction; - final Instruction branchTarget = branch.getTarget(); - branchVectors.add(new BranchVector(branch, branchTarget)); - } - } - // Sort the branch vectors. The natural order is essentially by from address. Note that this is not the same as start address.. back edges would be the exceptions - Collections.sort(branchVectors, branchInfoComparator); - - return (branchVectors); - } - - void edump(StringBuilder _sb, Instruction i, boolean clone) { - final String label = InstructionHelper.getLabel(i, false, true, true); - - if (i instanceof CloneInstruction) { - edump(_sb, ((CloneInstruction) i).getReal(), true); - } else { - - if (i.producesStack()) { - _sb.append(" "); - } else { - _sb.append("! "); - } - - if (clone) { - _sb.append("*"); - } else { - _sb.append(" "); - } - _sb.append(i.getThisPC() + ":" + label); - } - - } - - void fdump(int _depth, Instruction i, boolean clone) { - final String label = i.getByteCode().getName();// InstructionHelper.getLabel(i, false, false, false); - - if (i instanceof CloneInstruction) { - fdump(_depth, ((CloneInstruction) i).getReal(), true); - } else { - if (_depth == 0) { - if (i.producesStack()) { - System.out.print(" "); - } else { - System.out.print("! "); - } - } - - if (clone) { - System.out.print("*"); - } else if (_depth == 0) { - System.out.print(" "); - } - System.out.print(i.getThisPC() + ":" + label); - } - if (i.getFirstChild() != null) { - // int child=0; - System.out.print("{"); - boolean comma = false; - for (Instruction ii = i.getFirstChild(); ii != null; ii = ii.getNextExpr()) { - if (comma) { - System.out.print(" ,"); - } - // System.out.print("<"+child+">"); - fdump(_depth + 1, ii, false); - comma = true; - // child++; - } - System.out.print("}"); - } - } - - void dump(String _indent, Instruction i, boolean clone) { - final String label = InstructionHelper.getLabel(i, true, false, false); - - if (i instanceof CloneInstruction) { - dump(_indent, ((CloneInstruction) i).getReal(), true); - } else { - System.out.println(_indent + (clone ? "*" : " ") + label); - } - for (Instruction ii = i.getFirstChild(); ii != null; ii = ii.getNextExpr()) { - dump(_indent + " ", ii, false); - - } - } - -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.tool; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import com.aparapi.internal.exception.CodeGenException; +import com.aparapi.internal.instruction.Instruction; +import com.aparapi.internal.instruction.InstructionSet.AssignToLocalVariable; +import com.aparapi.internal.instruction.InstructionSet.Branch; +import com.aparapi.internal.instruction.InstructionSet.ByteCode; +import com.aparapi.internal.instruction.InstructionSet.CloneInstruction; +import com.aparapi.internal.instruction.InstructionSet.CompositeInstruction; +import com.aparapi.internal.instruction.InstructionSet.ConditionalBranch16; +import com.aparapi.internal.instruction.InstructionSet.Constant; +import com.aparapi.internal.instruction.InstructionSet.FieldReference; +import com.aparapi.internal.instruction.InstructionSet.I_ACONST_NULL; +import com.aparapi.internal.instruction.InstructionSet.I_IINC; +import com.aparapi.internal.instruction.InstructionSet.LocalVariableTableIndexAccessor; +import com.aparapi.internal.instruction.InstructionSet.MethodCall; +import com.aparapi.internal.instruction.InstructionSet.OperatorInstruction; +import com.aparapi.internal.model.ClassModel; +import com.aparapi.internal.model.Entrypoint; +import com.aparapi.internal.model.MethodModel; +import com.aparapi.internal.model.ClassModel.LocalVariableInfo; +import com.aparapi.internal.writer.BlockWriter; + +public class InstructionHelper{ + + public static class Table{ + + final static String spaces = " "; + + private final List<Table.Col> cols = new ArrayList<Table.Col>(); + + private int size = 0; + + private int col = 0; + + public static class Col{ + private final List<String> text = new ArrayList<String>(); + + private int width; + + private String format = "%s"; + + public Col(String _format) { + format = _format; + } + + public Col() { + this("%s"); + } + + public void format(Object... args) { + final String s = String.format(format, args); + + width = Math.max(s.length(), width); + text.add(s); + } + + public int size() { + return (text.size()); + } + + public String pad(String _s, int _width) { + final int length = _s.length(); + final int padWidth = _width - length; + final String padded = _s + spaces.substring(0, padWidth); + return (padded); + + } + + public String get(int _i) { + + return (pad(text.get(_i), width)); + } + + public void header(String _header) { + text.add(_header); + width = _header.length(); + } + } + + public Table(String... _formats) { + for (final String format : _formats) { + cols.add(new Col(format)); + } + } + + public void data(Object... args) { + cols.get(col++).format(args); + if (col == cols.size()) { + col = 0; + size++; + } + } + + @Override public String toString() { + final StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < size; i++) { + for (final Table.Col col : cols) { + sb.append(col.get(i)); + } + sb.append("\n"); + } + + return (sb.toString()); + } + + public void header(String... _headers) { + for (int i = 0; i < _headers.length; i++) { + cols.get(i).header(_headers[i]); + } + + size++; + } + } + + public static class StringWriter extends BlockWriter{ + private StringBuilder sb = null; + + public StringWriter(StringBuilder _sb) { + sb = _sb; + } + + public StringWriter() { + sb = new StringBuilder(); + } + + @Override public void write(String _string) { + sb.append(_string); + } + + @Override public String toString() { + return (sb.toString().trim()); + } + + public void clear() { + sb = new StringBuilder(); + } + + public static String write(MethodModel _methodModel) throws CodeGenException { + final StringWriter sw = new StringWriter(); + sw.writeMethodBody(_methodModel); + return (sw.toString()); + } + + @Override public void write(Entrypoint entryPoint) { + // TODO Auto-generated method stub + } + + @Override public void writeMethodBody(MethodModel _methodModel) throws CodeGenException { + super.writeMethodBody(_methodModel); + } + } + + public static class BranchVector{ + protected Instruction from; + + protected Instruction to; + + protected Instruction start; + + protected Instruction end; + + private boolean forward = false; + + public BranchVector(Instruction _from, Instruction _to) { + from = _from; + to = _to; + if (from.getThisPC() > to.getThisPC()) { + start = _to; + end = _from; + forward = false; + } else { + start = _from; + end = _to; + forward = true; + } + + } + + public boolean overlaps(BranchVector _other) { + final boolean overlap = ((start.getThisPC() < _other.start.getThisPC()) && (end.getThisPC() > _other.start.getThisPC()) && (end + .getThisPC() <= _other.end.getThisPC())) // + || ((_other.start.getThisPC() < start.getThisPC()) && (_other.start.getThisPC() > start.getThisPC()) && (_other.end + .getThisPC() <= end.getThisPC())); + + return (overlap); + } + + public Instruction getTo() { + return (to); + } + + public Instruction getFrom() { + return (from); + } + + public int getStartPC() { + return (start.getThisPC()); + } + + public int getEndPC() { + return (end.getThisPC()); + } + + public Instruction getStart() { + return (start); + } + + public Instruction getEnd() { + return (end); + } + + @Override public boolean equals(Object other) { + return ((other instanceof BranchVector) && ((other == this) || (((BranchVector) other).from + .equals(((BranchVector) other).to)))); + } + + @Override public int hashCode() { + return ((from.hashCode() * 31) + to.hashCode()); + + } + + public boolean isForward() { + return (forward); + } + + @Override public String toString() { + if (isForward()) { + return ("forward from " + getStart() + " to " + getEnd()); + } + return ("backward from " + getEnd() + " to " + getStart()); + } + + public boolean isConditionalBranch() { + return (getFrom().isBranch() && getFrom().asBranch().isConditional()); + } + + public boolean isBackward() { + return (!isForward()); + } + + public static final String NONE = " "; + + public static final String THROUGH = "|"; + + public static final String CONDITIONAL_START = "?"; + + public static final String UNCONDITIONAL_START = "-"; + + public static final String TOP_ARROW = "^"; + + public static final String BOTTOM_ARROW = "v"; + + public String render(int _pc) { + String returnString = NONE; + + if (isForward()) { + if (_pc == getStartPC()) { + returnString = isConditionalBranch() ? CONDITIONAL_START : UNCONDITIONAL_START; + } else if ((_pc > getStartPC()) && (_pc < getEndPC())) { + returnString = THROUGH; + } else if (_pc == getEndPC()) { + returnString = BOTTOM_ARROW; + } + } else { + if (_pc == getStartPC()) { + returnString = TOP_ARROW; + } else if ((_pc > getStartPC()) && (_pc < getEndPC())) { + returnString = THROUGH; + } else if (_pc == getEndPC()) { + returnString = isConditionalBranch() ? CONDITIONAL_START : UNCONDITIONAL_START; + } + } + return returnString; + } + + public String render(int _startPC, int _thisPC) { + String returnString = NONE; + if (isForward()) { + if (_startPC == getStartPC()) { + returnString = isConditionalBranch() ? CONDITIONAL_START : UNCONDITIONAL_START; + } else if ((_thisPC > getStartPC()) && (_startPC < getEndPC())) { + returnString = THROUGH; + } else if (_thisPC == getEndPC()) { + returnString = BOTTOM_ARROW; + } + } else { + if (_startPC == getStartPC()) { + returnString = TOP_ARROW; + } else if ((_thisPC > getStartPC()) && (_startPC < getEndPC())) { + returnString = THROUGH; + } else if (_thisPC == getEndPC()) { + returnString = isConditionalBranch() ? CONDITIONAL_START : UNCONDITIONAL_START; + } + } + + return returnString; + } + } + + public static String getLabel(Instruction instruction, boolean showNumber, boolean showExpressions, boolean verboseBytecodeLabels) { + + final ByteCode byteCode = instruction.getByteCode(); + final StringBuilder label = new StringBuilder(); + if (showNumber) { + label.append(String.format("%3d: ", instruction.getThisPC())); + } + + if (!showExpressions) { + final String byteCodeName = byteCode.getName(); + + if (!verboseBytecodeLabels) { + label.append(byteCodeName); + } else { + if (instruction instanceof ConditionalBranch16) { + final ConditionalBranch16 conditionalBranch16 = (ConditionalBranch16) instruction; + label.append(conditionalBranch16.getOperator().getText()); + label.append(" -> "); + label.append(conditionalBranch16.getTarget().getThisPC()); + } else if (instruction instanceof Branch) { + final Branch branch = (Branch) instruction; + label.append(" -> "); + label.append(branch.getTarget().getThisPC()); + } else if (instruction instanceof MethodCall) { + final MethodCall methodCall = (MethodCall) instruction; + label.append(methodCall.getConstantPoolMethodEntry().getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); + label.append(" "); + label.append(methodCall.getConstantPoolMethodEntry().getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8()); + } else if (instruction instanceof OperatorInstruction) { + final OperatorInstruction operatorInstruction = (OperatorInstruction) instruction; + label.append(operatorInstruction.getOperator().getText() + "(" + byteCodeName + ")"); + } else if (instruction instanceof FieldReference) { + final FieldReference field = (FieldReference) instruction; + label.append(field.getConstantPoolFieldEntry().getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); + label.append(field.getConstantPoolFieldEntry().getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8()); + } else if (instruction instanceof Constant<?>) { + final Constant<?> constant = (Constant<?>) instruction; + final Object value = constant.getValue(); + if (value != null) { + label.append(value); + } else { + if (instruction instanceof I_ACONST_NULL) { + label.append("null"); + } else { + label.append(byteCodeName); + } + } + } else if (instruction instanceof AssignToLocalVariable) { + + final AssignToLocalVariable assignToLocalVariable = (AssignToLocalVariable) instruction; + final LocalVariableInfo info = assignToLocalVariable.getLocalVariableInfo(); + + if (assignToLocalVariable.isDeclaration()) { + label.append(ClassModel.convert(info.getVariableDescriptor())); + } + + label.append(info == null ? "?" : info.getVariableName()); + label.append("="); + + } else if (instruction instanceof LocalVariableTableIndexAccessor) { + final LocalVariableTableIndexAccessor localVariableAccessor = (LocalVariableTableIndexAccessor) instruction; + final LocalVariableInfo info = localVariableAccessor.getLocalVariableInfo(); + label.append(info.getVariableName()); + + } else if (instruction instanceof I_IINC) { + + label.append(instruction.getByteCode()); + label.append(" " + ((I_IINC) instruction).getDelta()); + label.append(" " + ((I_IINC) instruction).getLocalVariableInfo().getVariableName()); + } else if (instruction instanceof CompositeInstruction) { + label.append("composite "); + label.append(instruction.getByteCode()); + } else { + label.append(byteCodeName); + } + } + } else { + final StringWriter writer = new StringWriter(label); + try { + writer.writeInstruction(instruction); + } catch (final CodeGenException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + writer.write("// exception " + e.getMessage()); + } + } + + return (label.toString()); + } + + private static void appendFoldedInstruction(Table _sl, String _prefix, Instruction _instruction) { + _sl.data(_instruction.getThisPC()); + _sl.data(_prefix + InstructionHelper.getLabel(_instruction, false, false, true)); + final int startPc = _instruction.getStartPC(); + final int thisPc = _instruction.getThisPC(); + + final StringBuilder sb = new StringBuilder(); + for (final BranchVector branchInfo : getBranches(_instruction.getMethod())) { + sb.append(branchInfo.render(startPc, thisPc)); + } + + _sl.data(sb.toString()); + for (Instruction child = _instruction.getFirstChild(); child != null; child = child.getNextExpr()) { + appendFoldedInstruction(_sl, _prefix + " ", child); + } + } + + static void writeExpression(String _prefix, Instruction _instruction) { + System.out.println(_prefix + InstructionHelper.getLabel(_instruction, true, true, false)); + } + + static String getFoldedView(MethodModel _methodModel) { + final Table sl = new Table("%4d", " %s", " %s"); + sl.header(" pc", " expression", " branches"); + for (Instruction root = _methodModel.getExprHead(); root != null; root = root.getNextExpr()) { + appendFoldedInstruction(sl, "", root); + } + return (sl.toString()); + } + + static String createView(MethodModel _methodModel, String _msg, Instruction _head) { + final Table table = new Table("[%2d-%2d] ", "%-60s", "%s"); + for (Instruction root = _head; root != null; root = root.getNextExpr()) { + + final String label = InstructionHelper.getLabel(root, false, true, false); + final StringBuilder sb = new StringBuilder(); + for (final BranchVector branchInfo : getBranches(_methodModel)) { + sb.append(branchInfo.render(root.getThisPC(), root.getStartPC())); + } + table.data(root.getStartPC(), root.getThisPC()); + table.data(label); + table.data(sb); + + } + return (_msg + "{\n" + table.toString() + "}\n"); + } + + static String createView(MethodModel _methodModel, String _msg, Instruction _head, Instruction _tail, + int _pcForwardBranchTargetCounts[]) { + final Table table = new Table("[%2d-%2d] ", "%-40s", "%s", "%3d"); + + for (Instruction root = _head; root != null; root = root.getNextExpr()) { + final String label = InstructionHelper.getLabel(root, false, false, false); + final StringBuilder sb = new StringBuilder(); + for (final BranchVector branchInfo : getBranches(_methodModel)) { + sb.append(branchInfo.render(root.getThisPC(), root.getStartPC())); + } + table.data(root.getStartPC(), root.getThisPC()); + table.data(" " + label); + table.data(sb); + table.data(_pcForwardBranchTargetCounts[root.getStartPC()]); + } + final String label = InstructionHelper.getLabel(_tail, false, false, false); + final StringBuilder sb = new StringBuilder(); + for (final BranchVector branchInfo : getBranches(_methodModel)) { + sb.append(branchInfo.render(_tail.getThisPC(), _tail.getStartPC())); + } + table.data(_tail.getStartPC(), _tail.getThisPC()); + table.data("[" + label + "]"); + table.data(sb); + table.data(_pcForwardBranchTargetCounts[_tail.getStartPC()]); + return (_msg + "{\n" + table.toString() + "}\n"); + } + + static String getJavapView(MethodModel _methodModel) { + final Table table = new Table("%4d", "%4d", " %s", " %s"); + table.header("stack ", "pc ", " mnemonic", " branches"); + int stack = 0; + for (Instruction i = _methodModel.getPCHead(); i != null; i = i.getNextPC()) { + stack += i.getStackDelta(); + final int pc = i.getThisPC(); + table.data(stack); + table.data(pc); + table.data(InstructionHelper.getLabel(i, false, false, false)); + if (true) { + final StringBuilder sb = new StringBuilder(); + for (final BranchVector branchInfo : getBranches(_methodModel)) { + sb.append(branchInfo.render(pc)); + } + table.data(sb); + } + + } + return (table.toString()); + } + + private static Comparator<BranchVector> branchInfoComparator = new Comparator<BranchVector>(){ + @Override public int compare(BranchVector left, BranchVector right) { + final int value = left.getFrom().compareTo(right.getFrom()); + return (value); + } + + }; + + static List<BranchVector> getBranches(MethodModel _methodModel) { + final List<BranchVector> branchVectors = new ArrayList<BranchVector>(); + + for (Instruction instruction = _methodModel.getPCHead(); instruction != null; instruction = instruction.getNextPC()) { + if (instruction.isBranch()) { + final Branch branch = (Branch) instruction; + final Instruction branchTarget = branch.getTarget(); + branchVectors.add(new BranchVector(branch, branchTarget)); + } + } + // Sort the branch vectors. The natural order is essentially by from address. Note that this is not the same as start address.. back edges would be the exceptions + Collections.sort(branchVectors, branchInfoComparator); + + return (branchVectors); + } + + void edump(StringBuilder _sb, Instruction i, boolean clone) { + final String label = InstructionHelper.getLabel(i, false, true, true); + + if (i instanceof CloneInstruction) { + edump(_sb, ((CloneInstruction) i).getReal(), true); + } else { + + if (i.producesStack()) { + _sb.append(" "); + } else { + _sb.append("! "); + } + + if (clone) { + _sb.append("*"); + } else { + _sb.append(" "); + } + _sb.append(i.getThisPC() + ":" + label); + } + + } + + void fdump(int _depth, Instruction i, boolean clone) { + final String label = i.getByteCode().getName();// InstructionHelper.getLabel(i, false, false, false); + + if (i instanceof CloneInstruction) { + fdump(_depth, ((CloneInstruction) i).getReal(), true); + } else { + if (_depth == 0) { + if (i.producesStack()) { + System.out.print(" "); + } else { + System.out.print("! "); + } + } + + if (clone) { + System.out.print("*"); + } else if (_depth == 0) { + System.out.print(" "); + } + System.out.print(i.getThisPC() + ":" + label); + } + if (i.getFirstChild() != null) { + // int child=0; + System.out.print("{"); + boolean comma = false; + for (Instruction ii = i.getFirstChild(); ii != null; ii = ii.getNextExpr()) { + if (comma) { + System.out.print(" ,"); + } + // System.out.print("<"+child+">"); + fdump(_depth + 1, ii, false); + comma = true; + // child++; + } + System.out.print("}"); + } + } + + void dump(String _indent, Instruction i, boolean clone) { + final String label = InstructionHelper.getLabel(i, true, false, false); + + if (i instanceof CloneInstruction) { + dump(_indent, ((CloneInstruction) i).getReal(), true); + } else { + System.out.println(_indent + (clone ? "*" : " ") + label); + } + for (Instruction ii = i.getFirstChild(); ii != null; ii = ii.getNextExpr()) { + dump(_indent + " ", ii, false); + + } + } + +} diff --git a/src/main/java/com/aparapi/internal/tool/InstructionViewer.java b/src/main/java/com/aparapi/internal/tool/InstructionViewer.java index 711540ad9ec15fb621f08087f0da4bf656b826c0..ce83f795296bbb910189d1d51adf76a29b228ed7 100644 --- a/src/main/java/com/aparapi/internal/tool/InstructionViewer.java +++ b/src/main/java/com/aparapi/internal/tool/InstructionViewer.java @@ -1,1132 +1,1132 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.tool; - -import java.awt.BasicStroke; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.Shape; -import java.awt.Stroke; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.CubicCurve2D; -import java.awt.image.BufferedImage; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComponent; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JToggleButton; -import javax.swing.JToolBar; -import javax.swing.SpringLayout; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import com.aparapi.Config; -import com.aparapi.internal.exception.AparapiException; -import com.aparapi.internal.exception.ClassParseException; -import com.aparapi.internal.instruction.Instruction; -import com.aparapi.internal.instruction.InstructionSet.CompositeInstruction; -import com.aparapi.internal.model.ClassModel; -import com.aparapi.internal.model.Entrypoint; -import com.aparapi.internal.model.MethodModel; -import com.aparapi.internal.tool.InstructionViewer.Form.Check; -import com.aparapi.internal.tool.InstructionViewer.Form.Template; -import com.aparapi.internal.tool.InstructionViewer.Form.Toggle; - -public class InstructionViewer implements Config.InstructionListener{ - - public static abstract class Form<T extends Form.Template> { - public @interface OneOf { - String label(); - - String[] options(); - } - - public interface Template{ - } - - @Retention(RetentionPolicy.RUNTIME) public @interface List { - Class<?> value(); - - } - - @Retention(RetentionPolicy.RUNTIME) public @interface Toggle { - String label(); - - String on(); - - String off(); - } - - @Retention(RetentionPolicy.RUNTIME) public @interface Check { - String label(); - } - - public final static int INSET = 5; - - private final T template; - - JPanel panel; - - private final SpringLayout layout = new SpringLayout(); - - void setBoolean(Field _field, boolean _value) { - try { - _field.setBoolean(template, _value); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - boolean getBoolean(Field _field) { - try { - return (_field.getBoolean(template)); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return (false); - } - - Object get(Field _field) { - try { - return (_field.get(template)); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return (null); - } - - public Form(T _template) { - template = _template; - panel = new JPanel(layout); - JComponent last = panel; - final Map<Field, JLabel> fieldToLabelMap = new LinkedHashMap<Field, JLabel>(); - Field fieldWithWidestLabel = null; - int fieldWithWidestLabelWidth = 0; - - // we need to know the widest Label so create the labels in one pass - for (final Field field : template.getClass().getFields()) { - String labelString = null; - - final Check checkAnnotation = field.getAnnotation(Check.class); - if (checkAnnotation != null) { - labelString = checkAnnotation.label(); - } else { - final Toggle toggleAnnotation = field.getAnnotation(Toggle.class); - if (toggleAnnotation != null) { - labelString = toggleAnnotation.label(); - } - } - if (labelString != null) { - final JLabel label = new JLabel(labelString); - panel.add(label); - - fieldToLabelMap.put(field, label); - if (labelString.length() > fieldWithWidestLabelWidth) { - fieldWithWidestLabel = field; - fieldWithWidestLabelWidth = labelString.length(); - } - } - } - - for (final Field field : fieldToLabelMap.keySet()) { - layout.putConstraint(SpringLayout.NORTH, fieldToLabelMap.get(field), INSET, (last == panel) ? SpringLayout.NORTH - : SpringLayout.SOUTH, last); - layout.putConstraint(SpringLayout.WEST, fieldToLabelMap.get(field), INSET, SpringLayout.WEST, panel); - JComponent newComponent = null; - - if (field.getType().isAssignableFrom(Boolean.TYPE)) { - final Field booleanField = field; - - final Toggle toggleAnnotation = field.getAnnotation(Toggle.class); - if (toggleAnnotation != null) { - final String toggleButtonOnLabel = toggleAnnotation.on(); - final String toggleButtonOffLabel = toggleAnnotation.off(); - final String toggleButtonLabel = getBoolean(field) ? toggleButtonOnLabel : toggleButtonOffLabel; - final JToggleButton toggleButton = new JToggleButton(toggleButtonLabel, getBoolean(field)); - toggleButton.addActionListener(new ActionListener(){ - @Override public void actionPerformed(ActionEvent _actionEvent) { - final JToggleButton toggleButton = ((JToggleButton) _actionEvent.getSource()); - // System.out.println("toggle toggle "+toggleButton); - if (toggleButton.getText().equals(toggleButtonOnLabel)) { - toggleButton.setText(toggleButtonOffLabel); - setBoolean(booleanField, false); - - } else { - toggleButton.setText(toggleButtonOnLabel); - setBoolean(booleanField, true); - - } - sync(); - - } - }); - newComponent = toggleButton; - } - final Check checkAnnotation = field.getAnnotation(Check.class); - if (checkAnnotation != null) { - final JCheckBox checkBox = new JCheckBox(); - checkBox.setSelected(getBoolean(field)); - - checkBox.addChangeListener(new ChangeListener(){ - - @Override public void stateChanged(ChangeEvent _changeEvent) { - - final JCheckBox checkBox = ((JCheckBox) _changeEvent.getSource()); - // System.out.println("check toggle "+checkBox); - setBoolean(booleanField, checkBox.isSelected()); - sync(); - - } - }); - newComponent = checkBox; - } - } - if (newComponent != null) { - panel.add(newComponent); - layout.putConstraint(SpringLayout.NORTH, newComponent, INSET, (last == panel) ? SpringLayout.NORTH - : SpringLayout.SOUTH, last); - layout.putConstraint(SpringLayout.WEST, newComponent, INSET, SpringLayout.EAST, - fieldToLabelMap.get(fieldWithWidestLabel)); - layout.putConstraint(SpringLayout.EAST, newComponent, INSET, SpringLayout.EAST, panel); - } - last = newComponent; - } - - layout.layoutContainer(panel); - - } - - public abstract void sync(); - - public Component getPanel() { - return (panel); - } - } - - public static final int VMARGIN = 2; - - public static final int HMARGIN = 2; - - public static final int HGAPROOT = 100; - - public static final int HGAP = 40; - - public static final int VGAP = 20; - - public static final int ARROWGAP = 5; - - public static final int EDGEGAP = 20; - - public static final int CURVEBOW = 20; - - public static class Options implements Template{ - - @Toggle(label = "Fold", on = "On", off = "Off") public boolean fold = true; - - @Check(label = "Fan Edges") public boolean edgeFan = true; - - @Check(label = "Curves") public boolean edgeCurve = false; - - @Check(label = "PC") public boolean showPc = true; - - @Check(label = "Bytecode Labels") public boolean verboseBytecodeLabels = false; - - @Check(label = "Collapse All") public boolean collapseAll = false; - - /* @Check(label = "Show expressions")*/public boolean showExpressions = false; - - } - - private static class XY{ - public XY(double _x, double _y) { - x = _x; - y = _y; - } - - double x, y; - } - - private static class View{ - AffineTransform offGraphicsTransform = new AffineTransform(); - - private double scale = 1; - - private double x; - - private double y; - - public double translatex(int _screenx) { - return ((_screenx - offGraphicsTransform.getTranslateX()) / offGraphicsTransform.getScaleX()); - - } - - public double screenx() { - return ((offGraphicsTransform.getScaleX() * x) + offGraphicsTransform.getTranslateX()); - } - - public double translatey(int _screeny) { - return ((_screeny - offGraphicsTransform.getTranslateY()) / offGraphicsTransform.getScaleY()); - } - - public double screeny() { - return ((offGraphicsTransform.getScaleY() * y) + offGraphicsTransform.getTranslateY()); - } - } - - private final JPanel container; - - private BufferedImage offscreen; - - private Dimension offscreensize; - - private Graphics2D offgraphics; - - public void dirty() { - dirty = true; - - container.repaint(); - } - - private boolean dirty = false; - - private final View view = new View(); - - private XY dragStart = null; - - public synchronized void draw(Graphics _g) { - - final Dimension containerSize = container.getSize(); - if (dirty || (offscreen == null) || (containerSize.width != offscreensize.width) - || (containerSize.height != offscreensize.height)) { - offscreensize = new Dimension(containerSize.width, containerSize.height); - offscreen = (BufferedImage) container.createImage(offscreensize.width, offscreensize.height); - - if (offgraphics != null) { - offgraphics.dispose(); - } - offgraphics = offscreen.createGraphics(); - - offgraphics.setFont(container.getFont()); - offgraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - offgraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - offgraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - // offgraphics.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); - offgraphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); - final AffineTransform offGraphicsTransform = new AffineTransform(); - offgraphics.setTransform(offGraphicsTransform); - offgraphics.setColor(container.getBackground()); - offgraphics.fillRect(0, 0, (offscreensize.width), (offscreensize.height)); - offGraphicsTransform.setToTranslation(view.screenx(), view.screeny()); - offGraphicsTransform.scale(view.scale, view.scale); - offgraphics.setTransform(offGraphicsTransform); - view.offGraphicsTransform = offGraphicsTransform; - dirty = false; - - } else { - offgraphics.setColor(container.getBackground()); - offgraphics.fillRect(0, 0, (offscreensize.width), (offscreensize.height)); - } - render(offgraphics); - _g.drawImage(offscreen, 0, 0, null); - - } - - public Component getContainer() { - return (container); - } - - public void text(Graphics2D _g, String _text, double _x, double _y) { - final FontMetrics fm = _g.getFontMetrics(); - _g.drawString(_text, (int) _x, (int) ((_y - fm.getAscent()) + fm.getHeight())); - - } - - public void text(Graphics2D _g, Color _color, String _text, double _x, double _y) { - final Color color = _g.getColor(); - _g.setColor(_color); - text(_g, _text, _x, _y); - _g.setColor(color); - - } - - public void line(Graphics2D _g, Stroke _stroke, double _x1, double _y1, double _x2, double _y2) { - final Stroke stroke = _g.getStroke(); - _g.setStroke(_stroke); - line(_g, _x1, _y1, _x2, _y2); - _g.setStroke(stroke); - } - - public void stroke(Graphics2D _g, Stroke _stroke, Shape _rect) { - final Stroke stroke = _g.getStroke(); - _g.setStroke(_stroke); - draw(_g, _rect); - _g.setStroke(stroke); - } - - public void fill(Graphics2D _g, Color _color, Shape _rect) { - final Color color = _g.getColor(); - _g.setColor(_color); - fill(_g, _rect); - _g.setColor(color); - } - - public void fillStroke(Graphics2D _g, Color _fillColor, Color _strokeColor, Stroke _stroke, Shape _rect) { - final Color color = _g.getColor(); - _g.setColor(_fillColor); - fill(_g, _rect); - _g.setColor(_strokeColor); - stroke(_g, _stroke, _rect); - _g.setColor(color); - } - - public void line(Graphics2D _g, double _x1, double _y1, double _x2, double _y2) { - _g.drawLine((int) _x1, (int) _y1, (int) _x2, (int) _y2); - } - - public void draw(Graphics2D _g, Shape _rectangle) { - _g.draw(_rectangle); - } - - public void fill(Graphics2D _g, Shape _rectangle) { - _g.fill(_rectangle); - } - - public Options config = new Options(); - - final private Color unselectedColor = Color.WHITE; - - final private Color selectedColor = Color.gray.brighter(); - - private final Stroke thickStroke = new BasicStroke((float) 2.0); - - private final Stroke thinStroke = new BasicStroke((float) 1.0); - - private final Stroke outlineStroke = new BasicStroke((float) 0.5); - - public Polygon arrowHeadOut = new Polygon(); - { - arrowHeadOut.addPoint(8, -4); - arrowHeadOut.addPoint(0, 0); - arrowHeadOut.addPoint(8, 4); - arrowHeadOut.addPoint(8, -4); - } - - Polygon arrowHeadIn = new Polygon(); - { - arrowHeadIn.addPoint(0, -4); - arrowHeadIn.addPoint(8, 0); - arrowHeadIn.addPoint(0, 4); - arrowHeadIn.addPoint(0, -4); - } - - public class InstructionView{ - - private final Instruction instruction; - - private Shape shape; - - public Instruction branchTarget; - - public Instruction collapsedBranchTarget; - - public String label; - - public boolean dim; - - public InstructionView(Instruction _instruction) { - instruction = _instruction; - } - - } - - private final Map<Instruction, InstructionView> locationToInstructionViewMap = new HashMap<Instruction, InstructionView>(); - - InstructionView getInstructionView(Instruction _instruction) { - - InstructionView instructionView = locationToInstructionViewMap.get(_instruction); - if (instructionView == null) { - locationToInstructionViewMap.put(_instruction, instructionView = new InstructionView(_instruction)); - - } - return (instructionView); - } - - double foldPlace(Graphics2D _g, InstructionView _instructionView, double _x, double _y, boolean _dim) { - _instructionView.dim = _dim; - final FontMetrics fm = _g.getFontMetrics(); - - _instructionView.label = InstructionHelper.getLabel(_instructionView.instruction, config.showPc, config.showExpressions, - config.verboseBytecodeLabels); - - final int w = fm.stringWidth(_instructionView.label) + HMARGIN; - final int h = fm.getHeight() + VMARGIN; - - double y = _y; - final double x = _x + w + (_instructionView.instruction.getRootExpr() == _instructionView.instruction ? HGAP : HGAP); - - if (!config.collapseAll && !config.showExpressions) { - - for (Instruction e = _instructionView.instruction.getFirstChild(); e != null; e = e.getNextExpr()) { - - y = foldPlace(_g, getInstructionView(e), x, y, _dim); - if (e != _instructionView.instruction.getLastChild()) { - y += VGAP; - } - } - - } - final double top = ((y + _y) / 2) - (h / 2); - _instructionView.shape = new Rectangle((int) _x, (int) top, w, h); - return (Math.max(_y, y)); - - } - - void foldRender(Graphics2D _g, InstructionView _instructionView) { - final Instruction instruction = _instructionView.instruction; - if (!config.collapseAll && !config.showExpressions) { - for (Instruction e = instruction.getFirstChild(); e != null; e = e.getNextExpr()) { - - foldRender(_g, getInstructionView(e)); - - } - } - if (_instructionView.dim) { - _g.setColor(unselectedColor); - } else { - _g.setColor(selectedColor); - } - _g.fill(_instructionView.shape); - _g.setColor(Color.black); - _g.setStroke(outlineStroke); - _g.draw(_instructionView.shape); - text(_g, _instructionView.label, _instructionView.shape.getBounds().getCenterX() - - (_instructionView.shape.getBounds().getWidth() / 2), _instructionView.shape.getBounds().getCenterY()); - - if (!config.collapseAll && !config.showExpressions) { - - if (config.edgeFan) { - - for (Instruction e = instruction.getFirstChild(); e != null; e = e.getNextExpr()) { - final InstructionView iv = getInstructionView(e); - final double x1 = _instructionView.shape.getBounds().getMaxX() + ARROWGAP; - - final double y1 = _instructionView.shape.getBounds().getCenterY(); - final double x2 = iv.shape.getBounds().getMinX() - 5; - final double y2 = iv.shape.getBounds().getCenterY(); - - if (config.edgeCurve) { - _g.draw(new CubicCurve2D.Double(x1, y1, x1 + CURVEBOW, y1, x2 - CURVEBOW, y2, x2, y2)); - } else { - final double dx = (x1 - x2); - final double dy = (y1 - y2); - - final AffineTransform transform = _g.getTransform(); - final double hypot = Math.hypot(dy, dx); - final double angle = Math.atan2(dy, dx); - _g.translate(x2, y2); - _g.rotate(angle); - line(_g, thickStroke, 0, 0, hypot, 0); - _g.fillPolygon(arrowHeadOut); - _g.setTransform(transform); - } - } - - } else { - - _g.setStroke(thickStroke); - if ((instruction.getFirstChild() != null) && (instruction.getFirstChild() != instruction.getLastChild())) { // >1 children - final InstructionView iv0 = getInstructionView(instruction.getFirstChild()); - final InstructionView ivn = getInstructionView(instruction.getLastChild()); - - final double midx = (_instructionView.shape.getBounds().getMaxX() + iv0.shape.getBounds().getMinX()) / 2; - line(_g, midx, iv0.shape.getBounds().getCenterY(), midx, ivn.shape.getBounds().getCenterY()); - line(_g, _instructionView.shape.getBounds().getMaxX() + ARROWGAP, _instructionView.shape.getBounds().getCenterY(), - midx, _instructionView.shape.getBounds().getCenterY()); - - for (Instruction e = instruction.getFirstChild(); e != null; e = e.getNextExpr()) { - final InstructionView iv = getInstructionView(e); - line(_g, midx, iv.shape.getBounds().getCenterY(), iv.shape.getBounds().getMinX() - ARROWGAP, iv.shape.getBounds() - .getCenterY()); - } - } else if (instruction.getFirstChild() != null) { // 1 child - final InstructionView iv = getInstructionView(instruction.getFirstChild()); - line(_g, _instructionView.shape.getBounds().getMaxX() + ARROWGAP, _instructionView.shape.getBounds().getCenterY(), - iv.shape.getBounds().getMinX() - ARROWGAP, iv.shape.getBounds().getCenterY()); - } - } - } - - } - - double flatPlace(Graphics2D _g, InstructionView _instructionView, double _x, double _y) { - final FontMetrics fm = _g.getFontMetrics(); - final Instruction instruction = _instructionView.instruction; - _instructionView.label = InstructionHelper.getLabel(instruction, config.showPc, config.showExpressions, - config.verboseBytecodeLabels); - - final int h = fm.getHeight() + 2; - final double top = (_y / 2) - (h / 2); - _instructionView.shape = new Rectangle((int) _x, (int) top, fm.stringWidth(_instructionView.label) + 2, h); - return (_y + h); - } - - void flatRender(Graphics2D _g, InstructionView _instructionView) { - _g.setColor(unselectedColor); - _g.fill(_instructionView.shape); - _g.setColor(Color.black); - stroke(_g, outlineStroke, _instructionView.shape); - text(_g, _instructionView.label, _instructionView.shape.getBounds().getCenterX() - - (_instructionView.shape.getBounds().getWidth() / 2), _instructionView.shape.getBounds().getCenterY()); - } - - ClassModel classModel = null; - - public InstructionViewer(Color _background, String _name) { - - try { - classModel = ClassModel.createClassModel(Class.forName(_name)); - } catch (final ClassParseException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final ClassNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - container = new JPanel(){ - /** - * - */ - private static final long serialVersionUID = 1L; - - @Override public void paintComponent(Graphics g) { - draw(g); - } - }; - container.setBackground(_background); - - final MouseAdapter mouseAdaptor = new MouseAdapter(){ - @Override public void mouseEntered(MouseEvent e) { - container.requestFocusInWindow(); - } - - @Override public void mouseDragged(MouseEvent e) { - // System.out.println("dragged"); - if (dragStart != null) { - view.x = view.translatex(e.getX()) - dragStart.x; - view.y = view.translatey(e.getY()) - dragStart.y; - dirty(); - } - - } - - @Override public void mousePressed(MouseEvent e) { - - if (e.getButton() == 1) { - dragStart = new XY(view.translatex(e.getX()), view.translatey(e.getY())); - dirty(); - - } else if (e.getButton() == 3) { - - if (select(view.translatex(e.getX()), view.translatey(e.getY()))) { - dirty(); - } - } - - } - - @Override public void mouseReleased(MouseEvent e) { - dragStart = null; - // container.repaint(); - } - - @Override public void mouseWheelMoved(MouseWheelEvent e) { - view.scale += e.getWheelRotation() / 10.0; - dirty(); - } - - }; - - final KeyAdapter keyAdaptor = new KeyAdapter(){ - @Override public void keyTyped(KeyEvent arg0) { - if ((arg0.getKeyChar() == '-') || (arg0.getKeyChar() == '+')) { - if (arg0.getKeyChar() == '-') { - view.scale -= .1; - } else { - view.scale += .1; - } - dirty(); - } - - } - - }; - container.addMouseMotionListener(mouseAdaptor); - container.addMouseListener(mouseAdaptor); - container.addMouseWheelListener(mouseAdaptor); - container.addKeyListener(keyAdaptor); - container.repaint(); - - } - - public InstructionViewer() { - - final JFrame frame = new JFrame(); - - final Color background = Color.WHITE; - final JPanel panel = new JPanel(new BorderLayout()); - final JMenuBar menuBar = new JMenuBar(); - - final JMenu fileMenu = new JMenu("File"); - fileMenu.setMnemonic(KeyEvent.VK_F); - final ActionListener closeActionListener = new ActionListener(){ - @Override public void actionPerformed(ActionEvent arg0) { - System.exit(1); - } - - }; - final ActionListener nextActionListener = new ActionListener(){ - @Override public void actionPerformed(ActionEvent arg0) { - doorbell.ring(); - - } - - }; - final JMenuItem closeMenuItem = new JMenuItem("Close"); - closeMenuItem.setMnemonic(KeyEvent.VK_C); - closeMenuItem.addActionListener(closeActionListener); - fileMenu.add(closeMenuItem); - menuBar.add(fileMenu); - menuBar.setEnabled(true); - frame.setJMenuBar(menuBar); - - // http://java.sun.com/docs/books/tutorial/uiswing/components/toolbar.html - final JToolBar toolBar = new JToolBar(); - final JButton closeButton = new JButton("Close"); - closeButton.addActionListener(closeActionListener); - toolBar.add(closeButton); - - final JButton nextButton = new JButton("Next"); - nextButton.addActionListener(nextActionListener); - toolBar.add(nextButton); - - panel.add(BorderLayout.PAGE_START, toolBar); - - container = new JPanel(){ - /** - * - */ - private static final long serialVersionUID = 1L; - - @Override public void paintComponent(Graphics g) { - draw(g); - } - }; - container.setBackground(Color.WHITE); - - final MouseAdapter mouseAdaptor = new MouseAdapter(){ - @Override public void mouseEntered(MouseEvent e) { - container.requestFocusInWindow(); - } - - @Override public void mouseDragged(MouseEvent e) { - // System.out.println("dragged"); - if (dragStart != null) { - view.x = view.translatex(e.getX()) - dragStart.x; - view.y = view.translatey(e.getY()) - dragStart.y; - dirty(); - } - - } - - @Override public void mousePressed(MouseEvent e) { - - if (e.getButton() == 1) { - dragStart = new XY(view.translatex(e.getX()), view.translatey(e.getY())); - dirty(); - - } else if (e.getButton() == 3) { - - if (select(view.translatex(e.getX()), view.translatey(e.getY()))) { - dirty(); - } - } - - } - - @Override public void mouseReleased(MouseEvent e) { - dragStart = null; - // container.repaint(); - } - - @Override public void mouseWheelMoved(MouseWheelEvent e) { - view.scale += e.getWheelRotation() / 10.0; - dirty(); - } - - }; - - final KeyAdapter keyAdaptor = new KeyAdapter(){ - @Override public void keyTyped(KeyEvent arg0) { - if ((arg0.getKeyChar() == '-') || (arg0.getKeyChar() == '+')) { - if (arg0.getKeyChar() == '-') { - view.scale -= .1; - } else { - view.scale += .1; - } - dirty(); - } - - } - - }; - container.addMouseMotionListener(mouseAdaptor); - container.addMouseListener(mouseAdaptor); - container.addMouseWheelListener(mouseAdaptor); - container.addKeyListener(keyAdaptor); - container.repaint(); - - panel.add(BorderLayout.CENTER, container); - - final JPanel controls = new JPanel(new BorderLayout()); - - final Form<Options> form = new Form<Options>(config){ - @Override public void sync() { - dirty(); - } - }; - controls.add(form.getPanel()); - - controls.setPreferredSize(new Dimension(200, 500)); - panel.add(BorderLayout.EAST, controls); - frame.setBackground(background); - frame.getContentPane().add(panel); - frame.setPreferredSize(new Dimension(1024, 1000)); - frame.pack(); - frame.setVisible(true); - - } - - public boolean select(double _x, double _y) { - for (Instruction l = first; l != null; l = l.getNextPC()) { - final InstructionView iv = getInstructionView(l); - if ((iv.shape != null) && iv.shape.contains(_x, _y)) { - - return (true); - } - } - return (false); - } - - public void render(Graphics2D _g) { - if (first != null) { - - if (config.fold) { - double y = 100; - final Instruction firstRoot = first.getRootExpr(); - final List<InstructionView> instructionViews = new ArrayList<InstructionView>(); - - Instruction lastInstruction = null; - for (Instruction instruction = firstRoot; instruction != null; instruction = instruction.getNextExpr()) { - final InstructionView iv = getInstructionView(instruction); - iv.dim = false; - y = foldPlace(_g, iv, 100, y, false) + VGAP; - instructionViews.add(iv); - lastInstruction = instruction; - } - lastInstruction.getRootExpr(); - while (lastInstruction instanceof CompositeInstruction) { - lastInstruction = lastInstruction.getLastChild(); - } - for (Instruction instruction = lastInstruction.getNextPC(); instruction != null; instruction = instruction.getNextPC()) { - - final InstructionView iv = getInstructionView(instruction); - iv.dim = true; - y = foldPlace(_g, iv, 100, y, true) + VGAP; - instructionViews.add(iv); - - } - - _g.setColor(Color.black); - - for (final InstructionView instructionView : instructionViews) { - if (instructionView.instruction.isBranch()) { - final Instruction rootFromInstruction = instructionView.instruction; - final Instruction rootToInstruction = instructionView.instruction.asBranch().getTarget(); - final InstructionView fromIv = getInstructionView(rootFromInstruction); - final InstructionView toIv = getInstructionView(rootToInstruction); - edge(_g, Color.BLACK, fromIv, toIv, null, null); - } - } - - InstructionView last = null; - - for (final InstructionView instructionView : instructionViews) { - - foldRender(_g, instructionView); - if (last != null) { - line(_g, thickStroke, 120, last.shape.getBounds().getMaxY(), 120, instructionView.shape.getBounds().getMinY()); - } - foldRender(_g, instructionView); - last = instructionView; - } - - } else { - double y = 100; - for (Instruction l = first; l != null; l = l.getNextPC()) { - - y = flatPlace(_g, getInstructionView(l), 100, y) + VGAP; - - } - - _g.setColor(Color.black); - for (Instruction l = first; l != null; l = l.getNextPC()) { - if (l.isBranch()) { - final Instruction rootFromInstruction = l; - final Instruction rootToInstruction = l.asBranch().getTarget(); - final InstructionView fromIv = getInstructionView(rootFromInstruction); - final InstructionView toIv = getInstructionView(rootToInstruction); - - edge(_g, Color.BLACK, fromIv, toIv, null, null); - } - - } - - InstructionView last = null; - for (Instruction l = first; l != null; l = l.getNextPC()) { - final InstructionView iv = getInstructionView(l); - - if (last != null) { - line(_g, thickStroke, 120, last.shape.getBounds().getMaxY(), 120, iv.shape.getBounds().getMinY()); - } - flatRender(_g, iv); - last = iv; - } - } - } - - } - - public void edge(Graphics2D _g, Color _color, InstructionView _branch, InstructionView _target, String _endLabel, - String _startLabel) { - - final int delta = _target.instruction.getThisPC() - _branch.instruction.getThisPC(); - final int adjust = 7 + Math.abs(delta); - final double y1 = (int) _branch.shape.getBounds().getMaxY(); - if (_target.shape != null) { - _g.setStroke(thinStroke); - final Color old = _g.getColor(); - _g.setColor(_color); - final double y2 = (int) _target.shape.getBounds().getMinY(); - if (delta > 0) { - - final double x1 = (int) _branch.shape.getBounds().getMinX() - EDGEGAP; - final double x2 = (int) _target.shape.getBounds().getMinX() - EDGEGAP; - - _g.draw(new CubicCurve2D.Double(x1, y1, x1 - adjust, y1, x1 - adjust, y2, x2, y2)); - - final AffineTransform transform = _g.getTransform(); - _g.translate(x2 - 5, y2); - _g.fillPolygon(arrowHeadIn); - _g.setTransform(transform); - - } else { - - final double x1 = (int) _branch.shape.getBounds().getMaxX() + EDGEGAP; - final double x2 = (int) _target.shape.getBounds().getMaxX() + EDGEGAP; - - _g.draw(new CubicCurve2D.Double(x1, y1, Math.max(x1, x2) + adjust, y1, Math.max(x1, x2) + adjust, y2, x2, y2)); - final AffineTransform transform = _g.getTransform(); - - _g.translate(x2 - 5, y2); - _g.fillPolygon(arrowHeadOut); - _g.setTransform(transform); - - } - _g.setColor(old); - } - } - - volatile Instruction first = null; - - volatile Instruction current = null; - - @Override public void showAndTell(String message, Instruction head, Instruction _instruction) { - - if (first == null) { - first = head; - } - current = _instruction; - dirty(); - doorbell.snooze(); - - } - - public static class DoorBell{ - volatile boolean notified = false; - - public synchronized void snooze() { - while (!notified) { - try { - this.wait(); - } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - notified = false; - } - - public synchronized void ring() { - notified = true; - notify(); - } - - } - - public static DoorBell doorbell = new DoorBell(); - - public static void main(String[] _args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, - UnsupportedLookAndFeelException, AparapiException { - - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - - final JFrame frame = new JFrame(); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - final Color background = Color.WHITE; - final JPanel panel = new JPanel(new BorderLayout()); - final JMenuBar menuBar = new JMenuBar(); - - final JMenu fileMenu = new JMenu("File"); - fileMenu.setMnemonic(KeyEvent.VK_F); - final ActionListener closeActionListener = new ActionListener(){ - @Override public void actionPerformed(ActionEvent arg0) { - System.exit(1); - } - - }; - final ActionListener nextActionListener = new ActionListener(){ - @Override public void actionPerformed(ActionEvent arg0) { - doorbell.ring(); - - } - - }; - final JMenuItem closeMenuItem = new JMenuItem("Close"); - closeMenuItem.setMnemonic(KeyEvent.VK_C); - closeMenuItem.addActionListener(closeActionListener); - fileMenu.add(closeMenuItem); - menuBar.add(fileMenu); - menuBar.setEnabled(true); - frame.setJMenuBar(menuBar); - - final InstructionViewer instructionViewer = new InstructionViewer(background, _args[0]); - - Config.instructionListener = instructionViewer; - // http://java.sun.com/docs/books/tutorial/uiswing/components/toolbar.html - final JToolBar toolBar = new JToolBar(); - final JButton closeButton = new JButton("Close"); - closeButton.addActionListener(closeActionListener); - toolBar.add(closeButton); - - final JButton nextButton = new JButton("Next"); - nextButton.addActionListener(nextActionListener); - toolBar.add(nextButton); - - panel.add(BorderLayout.PAGE_START, toolBar); - - panel.add(BorderLayout.CENTER, instructionViewer.getContainer()); - - final JPanel controls = new JPanel(new BorderLayout()); - - final Form<Options> form = new Form<Options>(instructionViewer.config){ - @Override public void sync() { - instructionViewer.dirty(); - } - }; - controls.add(form.getPanel()); - - controls.setPreferredSize(new Dimension(200, 500)); - panel.add(BorderLayout.EAST, controls); - frame.setBackground(background); - frame.getContentPane().add(panel); - frame.setPreferredSize(new Dimension(800, 1000)); - frame.pack(); - frame.setVisible(true); - - (new Thread(new Runnable(){ - - @Override public void run() { - - Entrypoint entrypoint; - try { - entrypoint = instructionViewer.classModel.getEntrypoint(); - final MethodModel method = entrypoint.getMethodModel(); - } catch (final AparapiException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - - })).start(); - - } - -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.tool; + +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.geom.AffineTransform; +import java.awt.geom.CubicCurve2D; +import java.awt.image.BufferedImage; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.SpringLayout; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import com.aparapi.Config; +import com.aparapi.internal.exception.AparapiException; +import com.aparapi.internal.exception.ClassParseException; +import com.aparapi.internal.instruction.Instruction; +import com.aparapi.internal.instruction.InstructionSet.CompositeInstruction; +import com.aparapi.internal.model.ClassModel; +import com.aparapi.internal.model.Entrypoint; +import com.aparapi.internal.model.MethodModel; +import com.aparapi.internal.tool.InstructionViewer.Form.Check; +import com.aparapi.internal.tool.InstructionViewer.Form.Template; +import com.aparapi.internal.tool.InstructionViewer.Form.Toggle; + +public class InstructionViewer implements Config.InstructionListener{ + + public static abstract class Form<T extends Form.Template> { + public @interface OneOf { + String label(); + + String[] options(); + } + + public interface Template{ + } + + @Retention(RetentionPolicy.RUNTIME) public @interface List { + Class<?> value(); + + } + + @Retention(RetentionPolicy.RUNTIME) public @interface Toggle { + String label(); + + String on(); + + String off(); + } + + @Retention(RetentionPolicy.RUNTIME) public @interface Check { + String label(); + } + + public final static int INSET = 5; + + private final T template; + + JPanel panel; + + private final SpringLayout layout = new SpringLayout(); + + void setBoolean(Field _field, boolean _value) { + try { + _field.setBoolean(template, _value); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + boolean getBoolean(Field _field) { + try { + return (_field.getBoolean(template)); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return (false); + } + + Object get(Field _field) { + try { + return (_field.get(template)); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return (null); + } + + public Form(T _template) { + template = _template; + panel = new JPanel(layout); + JComponent last = panel; + final Map<Field, JLabel> fieldToLabelMap = new LinkedHashMap<Field, JLabel>(); + Field fieldWithWidestLabel = null; + int fieldWithWidestLabelWidth = 0; + + // we need to know the widest Label so create the labels in one pass + for (final Field field : template.getClass().getFields()) { + String labelString = null; + + final Check checkAnnotation = field.getAnnotation(Check.class); + if (checkAnnotation != null) { + labelString = checkAnnotation.label(); + } else { + final Toggle toggleAnnotation = field.getAnnotation(Toggle.class); + if (toggleAnnotation != null) { + labelString = toggleAnnotation.label(); + } + } + if (labelString != null) { + final JLabel label = new JLabel(labelString); + panel.add(label); + + fieldToLabelMap.put(field, label); + if (labelString.length() > fieldWithWidestLabelWidth) { + fieldWithWidestLabel = field; + fieldWithWidestLabelWidth = labelString.length(); + } + } + } + + for (final Field field : fieldToLabelMap.keySet()) { + layout.putConstraint(SpringLayout.NORTH, fieldToLabelMap.get(field), INSET, (last == panel) ? SpringLayout.NORTH + : SpringLayout.SOUTH, last); + layout.putConstraint(SpringLayout.WEST, fieldToLabelMap.get(field), INSET, SpringLayout.WEST, panel); + JComponent newComponent = null; + + if (field.getType().isAssignableFrom(Boolean.TYPE)) { + final Field booleanField = field; + + final Toggle toggleAnnotation = field.getAnnotation(Toggle.class); + if (toggleAnnotation != null) { + final String toggleButtonOnLabel = toggleAnnotation.on(); + final String toggleButtonOffLabel = toggleAnnotation.off(); + final String toggleButtonLabel = getBoolean(field) ? toggleButtonOnLabel : toggleButtonOffLabel; + final JToggleButton toggleButton = new JToggleButton(toggleButtonLabel, getBoolean(field)); + toggleButton.addActionListener(new ActionListener(){ + @Override public void actionPerformed(ActionEvent _actionEvent) { + final JToggleButton toggleButton = ((JToggleButton) _actionEvent.getSource()); + // System.out.println("toggle toggle "+toggleButton); + if (toggleButton.getText().equals(toggleButtonOnLabel)) { + toggleButton.setText(toggleButtonOffLabel); + setBoolean(booleanField, false); + + } else { + toggleButton.setText(toggleButtonOnLabel); + setBoolean(booleanField, true); + + } + sync(); + + } + }); + newComponent = toggleButton; + } + final Check checkAnnotation = field.getAnnotation(Check.class); + if (checkAnnotation != null) { + final JCheckBox checkBox = new JCheckBox(); + checkBox.setSelected(getBoolean(field)); + + checkBox.addChangeListener(new ChangeListener(){ + + @Override public void stateChanged(ChangeEvent _changeEvent) { + + final JCheckBox checkBox = ((JCheckBox) _changeEvent.getSource()); + // System.out.println("check toggle "+checkBox); + setBoolean(booleanField, checkBox.isSelected()); + sync(); + + } + }); + newComponent = checkBox; + } + } + if (newComponent != null) { + panel.add(newComponent); + layout.putConstraint(SpringLayout.NORTH, newComponent, INSET, (last == panel) ? SpringLayout.NORTH + : SpringLayout.SOUTH, last); + layout.putConstraint(SpringLayout.WEST, newComponent, INSET, SpringLayout.EAST, + fieldToLabelMap.get(fieldWithWidestLabel)); + layout.putConstraint(SpringLayout.EAST, newComponent, INSET, SpringLayout.EAST, panel); + } + last = newComponent; + } + + layout.layoutContainer(panel); + + } + + public abstract void sync(); + + public Component getPanel() { + return (panel); + } + } + + public static final int VMARGIN = 2; + + public static final int HMARGIN = 2; + + public static final int HGAPROOT = 100; + + public static final int HGAP = 40; + + public static final int VGAP = 20; + + public static final int ARROWGAP = 5; + + public static final int EDGEGAP = 20; + + public static final int CURVEBOW = 20; + + public static class Options implements Template{ + + @Toggle(label = "Fold", on = "On", off = "Off") public boolean fold = true; + + @Check(label = "Fan Edges") public boolean edgeFan = true; + + @Check(label = "Curves") public boolean edgeCurve = false; + + @Check(label = "PC") public boolean showPc = true; + + @Check(label = "Bytecode Labels") public boolean verboseBytecodeLabels = false; + + @Check(label = "Collapse All") public boolean collapseAll = false; + + /* @Check(label = "Show expressions")*/public boolean showExpressions = false; + + } + + private static class XY{ + public XY(double _x, double _y) { + x = _x; + y = _y; + } + + double x, y; + } + + private static class View{ + AffineTransform offGraphicsTransform = new AffineTransform(); + + private double scale = 1; + + private double x; + + private double y; + + public double translatex(int _screenx) { + return ((_screenx - offGraphicsTransform.getTranslateX()) / offGraphicsTransform.getScaleX()); + + } + + public double screenx() { + return ((offGraphicsTransform.getScaleX() * x) + offGraphicsTransform.getTranslateX()); + } + + public double translatey(int _screeny) { + return ((_screeny - offGraphicsTransform.getTranslateY()) / offGraphicsTransform.getScaleY()); + } + + public double screeny() { + return ((offGraphicsTransform.getScaleY() * y) + offGraphicsTransform.getTranslateY()); + } + } + + private final JPanel container; + + private BufferedImage offscreen; + + private Dimension offscreensize; + + private Graphics2D offgraphics; + + public void dirty() { + dirty = true; + + container.repaint(); + } + + private boolean dirty = false; + + private final View view = new View(); + + private XY dragStart = null; + + public synchronized void draw(Graphics _g) { + + final Dimension containerSize = container.getSize(); + if (dirty || (offscreen == null) || (containerSize.width != offscreensize.width) + || (containerSize.height != offscreensize.height)) { + offscreensize = new Dimension(containerSize.width, containerSize.height); + offscreen = (BufferedImage) container.createImage(offscreensize.width, offscreensize.height); + + if (offgraphics != null) { + offgraphics.dispose(); + } + offgraphics = offscreen.createGraphics(); + + offgraphics.setFont(container.getFont()); + offgraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + offgraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + offgraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + // offgraphics.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + offgraphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); + final AffineTransform offGraphicsTransform = new AffineTransform(); + offgraphics.setTransform(offGraphicsTransform); + offgraphics.setColor(container.getBackground()); + offgraphics.fillRect(0, 0, (offscreensize.width), (offscreensize.height)); + offGraphicsTransform.setToTranslation(view.screenx(), view.screeny()); + offGraphicsTransform.scale(view.scale, view.scale); + offgraphics.setTransform(offGraphicsTransform); + view.offGraphicsTransform = offGraphicsTransform; + dirty = false; + + } else { + offgraphics.setColor(container.getBackground()); + offgraphics.fillRect(0, 0, (offscreensize.width), (offscreensize.height)); + } + render(offgraphics); + _g.drawImage(offscreen, 0, 0, null); + + } + + public Component getContainer() { + return (container); + } + + public void text(Graphics2D _g, String _text, double _x, double _y) { + final FontMetrics fm = _g.getFontMetrics(); + _g.drawString(_text, (int) _x, (int) ((_y - fm.getAscent()) + fm.getHeight())); + + } + + public void text(Graphics2D _g, Color _color, String _text, double _x, double _y) { + final Color color = _g.getColor(); + _g.setColor(_color); + text(_g, _text, _x, _y); + _g.setColor(color); + + } + + public void line(Graphics2D _g, Stroke _stroke, double _x1, double _y1, double _x2, double _y2) { + final Stroke stroke = _g.getStroke(); + _g.setStroke(_stroke); + line(_g, _x1, _y1, _x2, _y2); + _g.setStroke(stroke); + } + + public void stroke(Graphics2D _g, Stroke _stroke, Shape _rect) { + final Stroke stroke = _g.getStroke(); + _g.setStroke(_stroke); + draw(_g, _rect); + _g.setStroke(stroke); + } + + public void fill(Graphics2D _g, Color _color, Shape _rect) { + final Color color = _g.getColor(); + _g.setColor(_color); + fill(_g, _rect); + _g.setColor(color); + } + + public void fillStroke(Graphics2D _g, Color _fillColor, Color _strokeColor, Stroke _stroke, Shape _rect) { + final Color color = _g.getColor(); + _g.setColor(_fillColor); + fill(_g, _rect); + _g.setColor(_strokeColor); + stroke(_g, _stroke, _rect); + _g.setColor(color); + } + + public void line(Graphics2D _g, double _x1, double _y1, double _x2, double _y2) { + _g.drawLine((int) _x1, (int) _y1, (int) _x2, (int) _y2); + } + + public void draw(Graphics2D _g, Shape _rectangle) { + _g.draw(_rectangle); + } + + public void fill(Graphics2D _g, Shape _rectangle) { + _g.fill(_rectangle); + } + + public Options config = new Options(); + + final private Color unselectedColor = Color.WHITE; + + final private Color selectedColor = Color.gray.brighter(); + + private final Stroke thickStroke = new BasicStroke((float) 2.0); + + private final Stroke thinStroke = new BasicStroke((float) 1.0); + + private final Stroke outlineStroke = new BasicStroke((float) 0.5); + + public Polygon arrowHeadOut = new Polygon(); + { + arrowHeadOut.addPoint(8, -4); + arrowHeadOut.addPoint(0, 0); + arrowHeadOut.addPoint(8, 4); + arrowHeadOut.addPoint(8, -4); + } + + Polygon arrowHeadIn = new Polygon(); + { + arrowHeadIn.addPoint(0, -4); + arrowHeadIn.addPoint(8, 0); + arrowHeadIn.addPoint(0, 4); + arrowHeadIn.addPoint(0, -4); + } + + public class InstructionView{ + + private final Instruction instruction; + + private Shape shape; + + public Instruction branchTarget; + + public Instruction collapsedBranchTarget; + + public String label; + + public boolean dim; + + public InstructionView(Instruction _instruction) { + instruction = _instruction; + } + + } + + private final Map<Instruction, InstructionView> locationToInstructionViewMap = new HashMap<Instruction, InstructionView>(); + + InstructionView getInstructionView(Instruction _instruction) { + + InstructionView instructionView = locationToInstructionViewMap.get(_instruction); + if (instructionView == null) { + locationToInstructionViewMap.put(_instruction, instructionView = new InstructionView(_instruction)); + + } + return (instructionView); + } + + double foldPlace(Graphics2D _g, InstructionView _instructionView, double _x, double _y, boolean _dim) { + _instructionView.dim = _dim; + final FontMetrics fm = _g.getFontMetrics(); + + _instructionView.label = InstructionHelper.getLabel(_instructionView.instruction, config.showPc, config.showExpressions, + config.verboseBytecodeLabels); + + final int w = fm.stringWidth(_instructionView.label) + HMARGIN; + final int h = fm.getHeight() + VMARGIN; + + double y = _y; + final double x = _x + w + (_instructionView.instruction.getRootExpr() == _instructionView.instruction ? HGAP : HGAP); + + if (!config.collapseAll && !config.showExpressions) { + + for (Instruction e = _instructionView.instruction.getFirstChild(); e != null; e = e.getNextExpr()) { + + y = foldPlace(_g, getInstructionView(e), x, y, _dim); + if (e != _instructionView.instruction.getLastChild()) { + y += VGAP; + } + } + + } + final double top = ((y + _y) / 2) - (h / 2); + _instructionView.shape = new Rectangle((int) _x, (int) top, w, h); + return (Math.max(_y, y)); + + } + + void foldRender(Graphics2D _g, InstructionView _instructionView) { + final Instruction instruction = _instructionView.instruction; + if (!config.collapseAll && !config.showExpressions) { + for (Instruction e = instruction.getFirstChild(); e != null; e = e.getNextExpr()) { + + foldRender(_g, getInstructionView(e)); + + } + } + if (_instructionView.dim) { + _g.setColor(unselectedColor); + } else { + _g.setColor(selectedColor); + } + _g.fill(_instructionView.shape); + _g.setColor(Color.black); + _g.setStroke(outlineStroke); + _g.draw(_instructionView.shape); + text(_g, _instructionView.label, _instructionView.shape.getBounds().getCenterX() + - (_instructionView.shape.getBounds().getWidth() / 2), _instructionView.shape.getBounds().getCenterY()); + + if (!config.collapseAll && !config.showExpressions) { + + if (config.edgeFan) { + + for (Instruction e = instruction.getFirstChild(); e != null; e = e.getNextExpr()) { + final InstructionView iv = getInstructionView(e); + final double x1 = _instructionView.shape.getBounds().getMaxX() + ARROWGAP; + + final double y1 = _instructionView.shape.getBounds().getCenterY(); + final double x2 = iv.shape.getBounds().getMinX() - 5; + final double y2 = iv.shape.getBounds().getCenterY(); + + if (config.edgeCurve) { + _g.draw(new CubicCurve2D.Double(x1, y1, x1 + CURVEBOW, y1, x2 - CURVEBOW, y2, x2, y2)); + } else { + final double dx = (x1 - x2); + final double dy = (y1 - y2); + + final AffineTransform transform = _g.getTransform(); + final double hypot = Math.hypot(dy, dx); + final double angle = Math.atan2(dy, dx); + _g.translate(x2, y2); + _g.rotate(angle); + line(_g, thickStroke, 0, 0, hypot, 0); + _g.fillPolygon(arrowHeadOut); + _g.setTransform(transform); + } + } + + } else { + + _g.setStroke(thickStroke); + if ((instruction.getFirstChild() != null) && (instruction.getFirstChild() != instruction.getLastChild())) { // >1 children + final InstructionView iv0 = getInstructionView(instruction.getFirstChild()); + final InstructionView ivn = getInstructionView(instruction.getLastChild()); + + final double midx = (_instructionView.shape.getBounds().getMaxX() + iv0.shape.getBounds().getMinX()) / 2; + line(_g, midx, iv0.shape.getBounds().getCenterY(), midx, ivn.shape.getBounds().getCenterY()); + line(_g, _instructionView.shape.getBounds().getMaxX() + ARROWGAP, _instructionView.shape.getBounds().getCenterY(), + midx, _instructionView.shape.getBounds().getCenterY()); + + for (Instruction e = instruction.getFirstChild(); e != null; e = e.getNextExpr()) { + final InstructionView iv = getInstructionView(e); + line(_g, midx, iv.shape.getBounds().getCenterY(), iv.shape.getBounds().getMinX() - ARROWGAP, iv.shape.getBounds() + .getCenterY()); + } + } else if (instruction.getFirstChild() != null) { // 1 child + final InstructionView iv = getInstructionView(instruction.getFirstChild()); + line(_g, _instructionView.shape.getBounds().getMaxX() + ARROWGAP, _instructionView.shape.getBounds().getCenterY(), + iv.shape.getBounds().getMinX() - ARROWGAP, iv.shape.getBounds().getCenterY()); + } + } + } + + } + + double flatPlace(Graphics2D _g, InstructionView _instructionView, double _x, double _y) { + final FontMetrics fm = _g.getFontMetrics(); + final Instruction instruction = _instructionView.instruction; + _instructionView.label = InstructionHelper.getLabel(instruction, config.showPc, config.showExpressions, + config.verboseBytecodeLabels); + + final int h = fm.getHeight() + 2; + final double top = (_y / 2) - (h / 2); + _instructionView.shape = new Rectangle((int) _x, (int) top, fm.stringWidth(_instructionView.label) + 2, h); + return (_y + h); + } + + void flatRender(Graphics2D _g, InstructionView _instructionView) { + _g.setColor(unselectedColor); + _g.fill(_instructionView.shape); + _g.setColor(Color.black); + stroke(_g, outlineStroke, _instructionView.shape); + text(_g, _instructionView.label, _instructionView.shape.getBounds().getCenterX() + - (_instructionView.shape.getBounds().getWidth() / 2), _instructionView.shape.getBounds().getCenterY()); + } + + ClassModel classModel = null; + + public InstructionViewer(Color _background, String _name) { + + try { + classModel = ClassModel.createClassModel(Class.forName(_name)); + } catch (final ClassParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + container = new JPanel(){ + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override public void paintComponent(Graphics g) { + draw(g); + } + }; + container.setBackground(_background); + + final MouseAdapter mouseAdaptor = new MouseAdapter(){ + @Override public void mouseEntered(MouseEvent e) { + container.requestFocusInWindow(); + } + + @Override public void mouseDragged(MouseEvent e) { + // System.out.println("dragged"); + if (dragStart != null) { + view.x = view.translatex(e.getX()) - dragStart.x; + view.y = view.translatey(e.getY()) - dragStart.y; + dirty(); + } + + } + + @Override public void mousePressed(MouseEvent e) { + + if (e.getButton() == 1) { + dragStart = new XY(view.translatex(e.getX()), view.translatey(e.getY())); + dirty(); + + } else if (e.getButton() == 3) { + + if (select(view.translatex(e.getX()), view.translatey(e.getY()))) { + dirty(); + } + } + + } + + @Override public void mouseReleased(MouseEvent e) { + dragStart = null; + // container.repaint(); + } + + @Override public void mouseWheelMoved(MouseWheelEvent e) { + view.scale += e.getWheelRotation() / 10.0; + dirty(); + } + + }; + + final KeyAdapter keyAdaptor = new KeyAdapter(){ + @Override public void keyTyped(KeyEvent arg0) { + if ((arg0.getKeyChar() == '-') || (arg0.getKeyChar() == '+')) { + if (arg0.getKeyChar() == '-') { + view.scale -= .1; + } else { + view.scale += .1; + } + dirty(); + } + + } + + }; + container.addMouseMotionListener(mouseAdaptor); + container.addMouseListener(mouseAdaptor); + container.addMouseWheelListener(mouseAdaptor); + container.addKeyListener(keyAdaptor); + container.repaint(); + + } + + public InstructionViewer() { + + final JFrame frame = new JFrame(); + + final Color background = Color.WHITE; + final JPanel panel = new JPanel(new BorderLayout()); + final JMenuBar menuBar = new JMenuBar(); + + final JMenu fileMenu = new JMenu("File"); + fileMenu.setMnemonic(KeyEvent.VK_F); + final ActionListener closeActionListener = new ActionListener(){ + @Override public void actionPerformed(ActionEvent arg0) { + System.exit(1); + } + + }; + final ActionListener nextActionListener = new ActionListener(){ + @Override public void actionPerformed(ActionEvent arg0) { + doorbell.ring(); + + } + + }; + final JMenuItem closeMenuItem = new JMenuItem("Close"); + closeMenuItem.setMnemonic(KeyEvent.VK_C); + closeMenuItem.addActionListener(closeActionListener); + fileMenu.add(closeMenuItem); + menuBar.add(fileMenu); + menuBar.setEnabled(true); + frame.setJMenuBar(menuBar); + + // http://java.sun.com/docs/books/tutorial/uiswing/components/toolbar.html + final JToolBar toolBar = new JToolBar(); + final JButton closeButton = new JButton("Close"); + closeButton.addActionListener(closeActionListener); + toolBar.add(closeButton); + + final JButton nextButton = new JButton("Next"); + nextButton.addActionListener(nextActionListener); + toolBar.add(nextButton); + + panel.add(BorderLayout.PAGE_START, toolBar); + + container = new JPanel(){ + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override public void paintComponent(Graphics g) { + draw(g); + } + }; + container.setBackground(Color.WHITE); + + final MouseAdapter mouseAdaptor = new MouseAdapter(){ + @Override public void mouseEntered(MouseEvent e) { + container.requestFocusInWindow(); + } + + @Override public void mouseDragged(MouseEvent e) { + // System.out.println("dragged"); + if (dragStart != null) { + view.x = view.translatex(e.getX()) - dragStart.x; + view.y = view.translatey(e.getY()) - dragStart.y; + dirty(); + } + + } + + @Override public void mousePressed(MouseEvent e) { + + if (e.getButton() == 1) { + dragStart = new XY(view.translatex(e.getX()), view.translatey(e.getY())); + dirty(); + + } else if (e.getButton() == 3) { + + if (select(view.translatex(e.getX()), view.translatey(e.getY()))) { + dirty(); + } + } + + } + + @Override public void mouseReleased(MouseEvent e) { + dragStart = null; + // container.repaint(); + } + + @Override public void mouseWheelMoved(MouseWheelEvent e) { + view.scale += e.getWheelRotation() / 10.0; + dirty(); + } + + }; + + final KeyAdapter keyAdaptor = new KeyAdapter(){ + @Override public void keyTyped(KeyEvent arg0) { + if ((arg0.getKeyChar() == '-') || (arg0.getKeyChar() == '+')) { + if (arg0.getKeyChar() == '-') { + view.scale -= .1; + } else { + view.scale += .1; + } + dirty(); + } + + } + + }; + container.addMouseMotionListener(mouseAdaptor); + container.addMouseListener(mouseAdaptor); + container.addMouseWheelListener(mouseAdaptor); + container.addKeyListener(keyAdaptor); + container.repaint(); + + panel.add(BorderLayout.CENTER, container); + + final JPanel controls = new JPanel(new BorderLayout()); + + final Form<Options> form = new Form<Options>(config){ + @Override public void sync() { + dirty(); + } + }; + controls.add(form.getPanel()); + + controls.setPreferredSize(new Dimension(200, 500)); + panel.add(BorderLayout.EAST, controls); + frame.setBackground(background); + frame.getContentPane().add(panel); + frame.setPreferredSize(new Dimension(1024, 1000)); + frame.pack(); + frame.setVisible(true); + + } + + public boolean select(double _x, double _y) { + for (Instruction l = first; l != null; l = l.getNextPC()) { + final InstructionView iv = getInstructionView(l); + if ((iv.shape != null) && iv.shape.contains(_x, _y)) { + + return (true); + } + } + return (false); + } + + public void render(Graphics2D _g) { + if (first != null) { + + if (config.fold) { + double y = 100; + final Instruction firstRoot = first.getRootExpr(); + final List<InstructionView> instructionViews = new ArrayList<InstructionView>(); + + Instruction lastInstruction = null; + for (Instruction instruction = firstRoot; instruction != null; instruction = instruction.getNextExpr()) { + final InstructionView iv = getInstructionView(instruction); + iv.dim = false; + y = foldPlace(_g, iv, 100, y, false) + VGAP; + instructionViews.add(iv); + lastInstruction = instruction; + } + lastInstruction.getRootExpr(); + while (lastInstruction instanceof CompositeInstruction) { + lastInstruction = lastInstruction.getLastChild(); + } + for (Instruction instruction = lastInstruction.getNextPC(); instruction != null; instruction = instruction.getNextPC()) { + + final InstructionView iv = getInstructionView(instruction); + iv.dim = true; + y = foldPlace(_g, iv, 100, y, true) + VGAP; + instructionViews.add(iv); + + } + + _g.setColor(Color.black); + + for (final InstructionView instructionView : instructionViews) { + if (instructionView.instruction.isBranch()) { + final Instruction rootFromInstruction = instructionView.instruction; + final Instruction rootToInstruction = instructionView.instruction.asBranch().getTarget(); + final InstructionView fromIv = getInstructionView(rootFromInstruction); + final InstructionView toIv = getInstructionView(rootToInstruction); + edge(_g, Color.BLACK, fromIv, toIv, null, null); + } + } + + InstructionView last = null; + + for (final InstructionView instructionView : instructionViews) { + + foldRender(_g, instructionView); + if (last != null) { + line(_g, thickStroke, 120, last.shape.getBounds().getMaxY(), 120, instructionView.shape.getBounds().getMinY()); + } + foldRender(_g, instructionView); + last = instructionView; + } + + } else { + double y = 100; + for (Instruction l = first; l != null; l = l.getNextPC()) { + + y = flatPlace(_g, getInstructionView(l), 100, y) + VGAP; + + } + + _g.setColor(Color.black); + for (Instruction l = first; l != null; l = l.getNextPC()) { + if (l.isBranch()) { + final Instruction rootFromInstruction = l; + final Instruction rootToInstruction = l.asBranch().getTarget(); + final InstructionView fromIv = getInstructionView(rootFromInstruction); + final InstructionView toIv = getInstructionView(rootToInstruction); + + edge(_g, Color.BLACK, fromIv, toIv, null, null); + } + + } + + InstructionView last = null; + for (Instruction l = first; l != null; l = l.getNextPC()) { + final InstructionView iv = getInstructionView(l); + + if (last != null) { + line(_g, thickStroke, 120, last.shape.getBounds().getMaxY(), 120, iv.shape.getBounds().getMinY()); + } + flatRender(_g, iv); + last = iv; + } + } + } + + } + + public void edge(Graphics2D _g, Color _color, InstructionView _branch, InstructionView _target, String _endLabel, + String _startLabel) { + + final int delta = _target.instruction.getThisPC() - _branch.instruction.getThisPC(); + final int adjust = 7 + Math.abs(delta); + final double y1 = (int) _branch.shape.getBounds().getMaxY(); + if (_target.shape != null) { + _g.setStroke(thinStroke); + final Color old = _g.getColor(); + _g.setColor(_color); + final double y2 = (int) _target.shape.getBounds().getMinY(); + if (delta > 0) { + + final double x1 = (int) _branch.shape.getBounds().getMinX() - EDGEGAP; + final double x2 = (int) _target.shape.getBounds().getMinX() - EDGEGAP; + + _g.draw(new CubicCurve2D.Double(x1, y1, x1 - adjust, y1, x1 - adjust, y2, x2, y2)); + + final AffineTransform transform = _g.getTransform(); + _g.translate(x2 - 5, y2); + _g.fillPolygon(arrowHeadIn); + _g.setTransform(transform); + + } else { + + final double x1 = (int) _branch.shape.getBounds().getMaxX() + EDGEGAP; + final double x2 = (int) _target.shape.getBounds().getMaxX() + EDGEGAP; + + _g.draw(new CubicCurve2D.Double(x1, y1, Math.max(x1, x2) + adjust, y1, Math.max(x1, x2) + adjust, y2, x2, y2)); + final AffineTransform transform = _g.getTransform(); + + _g.translate(x2 - 5, y2); + _g.fillPolygon(arrowHeadOut); + _g.setTransform(transform); + + } + _g.setColor(old); + } + } + + volatile Instruction first = null; + + volatile Instruction current = null; + + @Override public void showAndTell(String message, Instruction head, Instruction _instruction) { + + if (first == null) { + first = head; + } + current = _instruction; + dirty(); + doorbell.snooze(); + + } + + public static class DoorBell{ + volatile boolean notified = false; + + public synchronized void snooze() { + while (!notified) { + try { + this.wait(); + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + notified = false; + } + + public synchronized void ring() { + notified = true; + notify(); + } + + } + + public static DoorBell doorbell = new DoorBell(); + + public static void main(String[] _args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, + UnsupportedLookAndFeelException, AparapiException { + + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + + final JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + final Color background = Color.WHITE; + final JPanel panel = new JPanel(new BorderLayout()); + final JMenuBar menuBar = new JMenuBar(); + + final JMenu fileMenu = new JMenu("File"); + fileMenu.setMnemonic(KeyEvent.VK_F); + final ActionListener closeActionListener = new ActionListener(){ + @Override public void actionPerformed(ActionEvent arg0) { + System.exit(1); + } + + }; + final ActionListener nextActionListener = new ActionListener(){ + @Override public void actionPerformed(ActionEvent arg0) { + doorbell.ring(); + + } + + }; + final JMenuItem closeMenuItem = new JMenuItem("Close"); + closeMenuItem.setMnemonic(KeyEvent.VK_C); + closeMenuItem.addActionListener(closeActionListener); + fileMenu.add(closeMenuItem); + menuBar.add(fileMenu); + menuBar.setEnabled(true); + frame.setJMenuBar(menuBar); + + final InstructionViewer instructionViewer = new InstructionViewer(background, _args[0]); + + Config.instructionListener = instructionViewer; + // http://java.sun.com/docs/books/tutorial/uiswing/components/toolbar.html + final JToolBar toolBar = new JToolBar(); + final JButton closeButton = new JButton("Close"); + closeButton.addActionListener(closeActionListener); + toolBar.add(closeButton); + + final JButton nextButton = new JButton("Next"); + nextButton.addActionListener(nextActionListener); + toolBar.add(nextButton); + + panel.add(BorderLayout.PAGE_START, toolBar); + + panel.add(BorderLayout.CENTER, instructionViewer.getContainer()); + + final JPanel controls = new JPanel(new BorderLayout()); + + final Form<Options> form = new Form<Options>(instructionViewer.config){ + @Override public void sync() { + instructionViewer.dirty(); + } + }; + controls.add(form.getPanel()); + + controls.setPreferredSize(new Dimension(200, 500)); + panel.add(BorderLayout.EAST, controls); + frame.setBackground(background); + frame.getContentPane().add(panel); + frame.setPreferredSize(new Dimension(800, 1000)); + frame.pack(); + frame.setVisible(true); + + (new Thread(new Runnable(){ + + @Override public void run() { + + Entrypoint entrypoint; + try { + entrypoint = instructionViewer.classModel.getEntrypoint(); + final MethodModel method = entrypoint.getMethodModel(); + } catch (final AparapiException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + })).start(); + + } + +} diff --git a/src/main/java/com/aparapi/internal/tool/package-info.java b/src/main/java/com/aparapi/internal/tool/package-info.java index a41bb28082626f4f61291e9a98560a59b0a5750d..566101b95811621511b36ae5b0b736050c7b6bf0 100644 --- a/src/main/java/com/aparapi/internal/tool/package-info.java +++ b/src/main/java/com/aparapi/internal/tool/package-info.java @@ -1,19 +1,19 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * - */ +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + */ package com.aparapi.internal.tool; \ No newline at end of file diff --git a/src/main/java/com/aparapi/internal/util/OpenCLUtil.java b/src/main/java/com/aparapi/internal/util/OpenCLUtil.java index f4f813979c208b6a6e788781a09b7d3482610be2..91933f6847d7363b02efc00fcaa602879fc5eac2 100644 --- a/src/main/java/com/aparapi/internal/util/OpenCLUtil.java +++ b/src/main/java/com/aparapi/internal/util/OpenCLUtil.java @@ -1,36 +1,36 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.util; - -import java.util.List; - -import com.aparapi.internal.opencl.OpenCLPlatform; - -/** - * This utility class encapsulates the necessary actions required to query underlying OpenCL information - */ -public class OpenCLUtil{ - - /** - * Retrieve a list of available OpenCL Platforms - * - * @return Available OpenCL Platforms - */ - public static List<OpenCLPlatform> getOpenCLPlatforms() { - final OpenCLPlatform ocp = new OpenCLPlatform(); - return ocp.getOpenCLPlatforms(); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.util; + +import java.util.List; + +import com.aparapi.internal.opencl.OpenCLPlatform; + +/** + * This utility class encapsulates the necessary actions required to query underlying OpenCL information + */ +public class OpenCLUtil{ + + /** + * Retrieve a list of available OpenCL Platforms + * + * @return Available OpenCL Platforms + */ + public static List<OpenCLPlatform> getOpenCLPlatforms() { + final OpenCLPlatform ocp = new OpenCLPlatform(); + return ocp.getOpenCLPlatforms(); + } +} diff --git a/src/main/java/com/aparapi/internal/util/Reflection.java b/src/main/java/com/aparapi/internal/util/Reflection.java index e6d41388b25437ec015b26016a1a6f2d7821da46..c411945dfc47406ccfa3369a487d8e5a84a69c16 100644 --- a/src/main/java/com/aparapi/internal/util/Reflection.java +++ b/src/main/java/com/aparapi/internal/util/Reflection.java @@ -1,33 +1,33 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.internal.util; - -/** - * Created by Barney on 03/09/2015. - */ -public class Reflection { - - /** Avoids getting dumb empty names for anonymous inners. */ - public static String getSimpleName(Class<?> klass) { - String simpleName = klass.getSimpleName(); - if (simpleName.isEmpty()) { - String fullName = klass.getName(); - int index = fullName.lastIndexOf('.'); - simpleName = (index < 0) ? fullName : fullName.substring(index + 1); - } - return simpleName; - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.internal.util; + +/** + * Created by Barney on 03/09/2015. + */ +public class Reflection { + + /** Avoids getting dumb empty names for anonymous inners. */ + public static String getSimpleName(Class<?> klass) { + String simpleName = klass.getSimpleName(); + if (simpleName.isEmpty()) { + String fullName = klass.getName(); + int index = fullName.lastIndexOf('.'); + simpleName = (index < 0) ? fullName : fullName.substring(index + 1); + } + return simpleName; + } +} diff --git a/src/main/java/com/aparapi/internal/util/UnsafeWrapper.java b/src/main/java/com/aparapi/internal/util/UnsafeWrapper.java index 670c13610f6725bbd403e4eefbf6179d4033eb95..b39543febe135a3494c42c856374399bcc099983 100644 --- a/src/main/java/com/aparapi/internal/util/UnsafeWrapper.java +++ b/src/main/java/com/aparapi/internal/util/UnsafeWrapper.java @@ -1,428 +1,428 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - -*/ -package com.aparapi.internal.util; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * A wrapper around sun.misc.Unsafe for handling atomic operations, copies from fields to arrays and vice versa. - * - * We avoid using <code>sun.misc.Unsafe</code> directly using reflection, mostly just to avoid getting 'unsafe' compiler errors. - * - * This might need to be changed if we start to see performance issues. - * - * @author gfrost - * - */ - -public class UnsafeWrapper{ - - private static Object unsafe; - - private static Method getIntVolatileMethod; - - private static Method arrayBaseOffsetMethod; - - private static Method arrayIndexScaleMethod; - - private static Method getObjectMethod; - - private static Method getIntMethod; - - private static Method getFloatMethod; - - private static Method getByteMethod; - - private static Method getBooleanMethod; - - private static Method getLongMethod; - - private static Method objectFieldOffsetMethod; - - private static Method putBooleanMethod; - - private static Method putIntMethod; - - private static Method putFloatMethod; - - private static Method putDoubleMethod; - - private static Method putByteMethod; - - private static Method putLongMethod; - - private static Method compareAndSwapIntMethod; - - static { - try { - final Class<?> uc = Class.forName("sun.misc.Unsafe"); - - final Field field = uc.getDeclaredField("theUnsafe"); - field.setAccessible(true); - unsafe = field.get(uc); - getIntVolatileMethod = uc.getDeclaredMethod("getIntVolatile", Object.class, long.class); - arrayBaseOffsetMethod = uc.getDeclaredMethod("arrayBaseOffset", Class.class); - arrayIndexScaleMethod = uc.getDeclaredMethod("arrayIndexScale", Class.class); - getObjectMethod = uc.getDeclaredMethod("getObject", Object.class, long.class); - getIntMethod = uc.getDeclaredMethod("getInt", Object.class, long.class); - getFloatMethod = uc.getDeclaredMethod("getFloat", Object.class, long.class); - getByteMethod = uc.getDeclaredMethod("getByte", Object.class, long.class); - getBooleanMethod = uc.getDeclaredMethod("getBoolean", Object.class, long.class); - getLongMethod = uc.getDeclaredMethod("getLong", Object.class, long.class); - objectFieldOffsetMethod = uc.getDeclaredMethod("objectFieldOffset", Field.class); - putBooleanMethod = uc.getDeclaredMethod("putBoolean", Object.class, long.class, boolean.class); - putIntMethod = uc.getDeclaredMethod("putInt", Object.class, long.class, int.class); - putFloatMethod = uc.getDeclaredMethod("putFloat", Object.class, long.class, float.class); - putDoubleMethod = uc.getDeclaredMethod("putDouble", Object.class, long.class, double.class); - putLongMethod = uc.getDeclaredMethod("putLong", Object.class, long.class, long.class); - putByteMethod = uc.getDeclaredMethod("putByte", Object.class, long.class, byte.class); - compareAndSwapIntMethod = uc.getDeclaredMethod("compareAndSwapInt", Object.class, long.class, int.class, int.class); - } catch (final SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final NoSuchFieldException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final ClassNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final NoSuchMethodException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - public static int atomicAdd(int[] _arr, int _index, int _delta) { - if ((_index < 0) || (_index >= _arr.length)) { - throw new IndexOutOfBoundsException("index " + _index); - } - - final long rawIndex = intArrayBase + ((long) _index * intArrayScale); - while (true) { - int current; - try { - current = (Integer) getIntVolatileMethod.invoke(unsafe, _arr, rawIndex); - final int next = current + _delta; - if ((Boolean) compareAndSwapIntMethod.invoke(unsafe, _arr, rawIndex, current, next)) { - return current; - } - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - public static int arrayBaseOffset(Class<?> _arrayClass) { - int offset = 0; - - try { - offset = (Integer) (arrayBaseOffsetMethod.invoke(unsafe, _arrayClass)); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - return (offset); - } - - public static int arrayIndexScale(Class<?> _arrayClass) { - int scale = 0; - try { - scale = (Integer) (arrayIndexScaleMethod.invoke(unsafe, _arrayClass)); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return scale; - } - - private static int intArrayBase = arrayBaseOffset(int[].class); - - private static int intArrayScale = arrayIndexScale(int[].class); - - public static Object getObject(Object _object, long _offset) { - Object object = null; - try { - object = getObjectMethod.invoke(unsafe, _object, _offset); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return (object); - } - - public static int getInt(Object _object, long _offset) { - int value = 0; - try { - value = (Integer) getIntMethod.invoke(unsafe, _object, _offset); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return value; - } - - public static float getFloat(Object _object, long _offset) { - float value = 0; - try { - value = (Float) getFloatMethod.invoke(unsafe, _object, _offset); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return value; - } - - public static byte getByte(Object _object, long _offset) { - byte value = 0; - try { - value = (Byte) getByteMethod.invoke(unsafe, _object, _offset); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return value; - } - - public static boolean getBoolean(Object _object, long _offset) { - boolean value = false; - try { - value = (Boolean) getBooleanMethod.invoke(unsafe, _object, _offset); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return value; - } - - public static long getLong(Object _object, long _offset) { - long value = 0; - try { - value = (Long) getLongMethod.invoke(unsafe, _object, _offset); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return value; - } - - public static void putBoolean(Object _object, long _offset, boolean _boolean) { - try { - putBooleanMethod.invoke(unsafe, _object, _offset, _boolean); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - public static void putFloat(Object _object, long _offset, float _float) { - try { - putFloatMethod.invoke(unsafe, _object, _offset, _float); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - public static void putInt(Object _object, long _offset, int _int) { - try { - putIntMethod.invoke(unsafe, _object, _offset, _int); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - public static void putDouble(Object _object, long _offset, double _double) { - try { - putDoubleMethod.invoke(unsafe, _object, _offset, _double); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - public static void putByte(Object _object, long _offset, byte _byte) { - try { - putByteMethod.invoke(unsafe, _object, _offset, _byte); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - public static void putLong(Object _object, long _offset, long _long) { - try { - putLongMethod.invoke(unsafe, _object, _offset, _long); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - public static long objectFieldOffset(Field _field) { - long offset = 0l; - try { - offset = (Long) objectFieldOffsetMethod.invoke(unsafe, _field); - } catch (final IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (final InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return offset; - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + +*/ +package com.aparapi.internal.util; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * A wrapper around sun.misc.Unsafe for handling atomic operations, copies from fields to arrays and vice versa. + * + * We avoid using <code>sun.misc.Unsafe</code> directly using reflection, mostly just to avoid getting 'unsafe' compiler errors. + * + * This might need to be changed if we start to see performance issues. + * + * @author gfrost + * + */ + +public class UnsafeWrapper{ + + private static Object unsafe; + + private static Method getIntVolatileMethod; + + private static Method arrayBaseOffsetMethod; + + private static Method arrayIndexScaleMethod; + + private static Method getObjectMethod; + + private static Method getIntMethod; + + private static Method getFloatMethod; + + private static Method getByteMethod; + + private static Method getBooleanMethod; + + private static Method getLongMethod; + + private static Method objectFieldOffsetMethod; + + private static Method putBooleanMethod; + + private static Method putIntMethod; + + private static Method putFloatMethod; + + private static Method putDoubleMethod; + + private static Method putByteMethod; + + private static Method putLongMethod; + + private static Method compareAndSwapIntMethod; + + static { + try { + final Class<?> uc = Class.forName("sun.misc.Unsafe"); + + final Field field = uc.getDeclaredField("theUnsafe"); + field.setAccessible(true); + unsafe = field.get(uc); + getIntVolatileMethod = uc.getDeclaredMethod("getIntVolatile", Object.class, long.class); + arrayBaseOffsetMethod = uc.getDeclaredMethod("arrayBaseOffset", Class.class); + arrayIndexScaleMethod = uc.getDeclaredMethod("arrayIndexScale", Class.class); + getObjectMethod = uc.getDeclaredMethod("getObject", Object.class, long.class); + getIntMethod = uc.getDeclaredMethod("getInt", Object.class, long.class); + getFloatMethod = uc.getDeclaredMethod("getFloat", Object.class, long.class); + getByteMethod = uc.getDeclaredMethod("getByte", Object.class, long.class); + getBooleanMethod = uc.getDeclaredMethod("getBoolean", Object.class, long.class); + getLongMethod = uc.getDeclaredMethod("getLong", Object.class, long.class); + objectFieldOffsetMethod = uc.getDeclaredMethod("objectFieldOffset", Field.class); + putBooleanMethod = uc.getDeclaredMethod("putBoolean", Object.class, long.class, boolean.class); + putIntMethod = uc.getDeclaredMethod("putInt", Object.class, long.class, int.class); + putFloatMethod = uc.getDeclaredMethod("putFloat", Object.class, long.class, float.class); + putDoubleMethod = uc.getDeclaredMethod("putDouble", Object.class, long.class, double.class); + putLongMethod = uc.getDeclaredMethod("putLong", Object.class, long.class, long.class); + putByteMethod = uc.getDeclaredMethod("putByte", Object.class, long.class, byte.class); + compareAndSwapIntMethod = uc.getDeclaredMethod("compareAndSwapInt", Object.class, long.class, int.class, int.class); + } catch (final SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final NoSuchFieldException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final NoSuchMethodException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public static int atomicAdd(int[] _arr, int _index, int _delta) { + if ((_index < 0) || (_index >= _arr.length)) { + throw new IndexOutOfBoundsException("index " + _index); + } + + final long rawIndex = intArrayBase + ((long) _index * intArrayScale); + while (true) { + int current; + try { + current = (Integer) getIntVolatileMethod.invoke(unsafe, _arr, rawIndex); + final int next = current + _delta; + if ((Boolean) compareAndSwapIntMethod.invoke(unsafe, _arr, rawIndex, current, next)) { + return current; + } + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + public static int arrayBaseOffset(Class<?> _arrayClass) { + int offset = 0; + + try { + offset = (Integer) (arrayBaseOffsetMethod.invoke(unsafe, _arrayClass)); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return (offset); + } + + public static int arrayIndexScale(Class<?> _arrayClass) { + int scale = 0; + try { + scale = (Integer) (arrayIndexScaleMethod.invoke(unsafe, _arrayClass)); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return scale; + } + + private static int intArrayBase = arrayBaseOffset(int[].class); + + private static int intArrayScale = arrayIndexScale(int[].class); + + public static Object getObject(Object _object, long _offset) { + Object object = null; + try { + object = getObjectMethod.invoke(unsafe, _object, _offset); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return (object); + } + + public static int getInt(Object _object, long _offset) { + int value = 0; + try { + value = (Integer) getIntMethod.invoke(unsafe, _object, _offset); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return value; + } + + public static float getFloat(Object _object, long _offset) { + float value = 0; + try { + value = (Float) getFloatMethod.invoke(unsafe, _object, _offset); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return value; + } + + public static byte getByte(Object _object, long _offset) { + byte value = 0; + try { + value = (Byte) getByteMethod.invoke(unsafe, _object, _offset); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return value; + } + + public static boolean getBoolean(Object _object, long _offset) { + boolean value = false; + try { + value = (Boolean) getBooleanMethod.invoke(unsafe, _object, _offset); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return value; + } + + public static long getLong(Object _object, long _offset) { + long value = 0; + try { + value = (Long) getLongMethod.invoke(unsafe, _object, _offset); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return value; + } + + public static void putBoolean(Object _object, long _offset, boolean _boolean) { + try { + putBooleanMethod.invoke(unsafe, _object, _offset, _boolean); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public static void putFloat(Object _object, long _offset, float _float) { + try { + putFloatMethod.invoke(unsafe, _object, _offset, _float); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public static void putInt(Object _object, long _offset, int _int) { + try { + putIntMethod.invoke(unsafe, _object, _offset, _int); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public static void putDouble(Object _object, long _offset, double _double) { + try { + putDoubleMethod.invoke(unsafe, _object, _offset, _double); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public static void putByte(Object _object, long _offset, byte _byte) { + try { + putByteMethod.invoke(unsafe, _object, _offset, _byte); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public static void putLong(Object _object, long _offset, long _long) { + try { + putLongMethod.invoke(unsafe, _object, _offset, _long); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public static long objectFieldOffset(Field _field) { + long offset = 0l; + try { + offset = (Long) objectFieldOffsetMethod.invoke(unsafe, _field); + } catch (final IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (final InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return offset; + } +} diff --git a/src/main/java/com/aparapi/internal/writer/KernelWriter.java b/src/main/java/com/aparapi/internal/writer/KernelWriter.java index 9de60797fe910db5286496dfa8984c9b8095b138..17c37e58b737b8cd599b6a2e08b3b1e2435de6c0 100644 --- a/src/main/java/com/aparapi/internal/writer/KernelWriter.java +++ b/src/main/java/com/aparapi/internal/writer/KernelWriter.java @@ -1,736 +1,736 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - - */ -package com.aparapi.internal.writer; - -import com.aparapi.*; -import com.aparapi.internal.exception.*; -import com.aparapi.internal.instruction.*; -import com.aparapi.internal.instruction.InstructionSet.*; -import com.aparapi.internal.model.*; -import com.aparapi.internal.model.ClassModel.AttributePool.*; -import com.aparapi.internal.model.ClassModel.AttributePool.RuntimeAnnotationsEntry.*; -import com.aparapi.internal.model.ClassModel.*; -import com.aparapi.internal.model.ClassModel.ConstantPool.*; - -import java.util.*; - -public abstract class KernelWriter extends BlockWriter{ - - private final String cvtBooleanToChar = "char "; - - private final String cvtBooleanArrayToCharStar = "char* "; - - private final String cvtByteToChar = "char "; - - private final String cvtByteArrayToCharStar = "char* "; - - private final String cvtCharToShort = "unsigned short "; - - private final String cvtCharArrayToShortStar = "unsigned short* "; - - private final String cvtIntArrayToIntStar = "int* "; - - private final String cvtFloatArrayToFloatStar = "float* "; - - private final String cvtDoubleArrayToDoubleStar = "double* "; - - private final String cvtLongArrayToLongStar = "long* "; - - private final String cvtShortArrayToShortStar = "short* "; - - /** When declaring a __private struct pointer field, we always omit the "__private" qualifier. This is because the NVidia OpenCL compiler, at time of writing - * erroneously complains about explicitly qualifying pointers with __private ("error: field may not be qualified with an address space"). - */ - private static final boolean IMPLICIT_PRIVATE_FIELDS = true; - - // private static Logger logger = Logger.getLogger(Config.getLoggerName()); - - private Entrypoint entryPoint = null; - - public final static Map<String, String> javaToCLIdentifierMap = new HashMap<String, String>(); - { - javaToCLIdentifierMap.put("getGlobalId()I", "get_global_id(0)"); - javaToCLIdentifierMap.put("getGlobalId(I)I", "get_global_id"); // no parenthesis if we are conveying args - javaToCLIdentifierMap.put("getGlobalX()I", "get_global_id(0)"); - javaToCLIdentifierMap.put("getGlobalY()I", "get_global_id(1)"); - javaToCLIdentifierMap.put("getGlobalZ()I", "get_global_id(2)"); - - javaToCLIdentifierMap.put("getGlobalSize()I", "get_global_size(0)"); - javaToCLIdentifierMap.put("getGlobalSize(I)I", "get_global_size"); // no parenthesis if we are conveying args - javaToCLIdentifierMap.put("getGlobalWidth()I", "get_global_size(0)"); - javaToCLIdentifierMap.put("getGlobalHeight()I", "get_global_size(1)"); - javaToCLIdentifierMap.put("getGlobalDepth()I", "get_global_size(2)"); - - javaToCLIdentifierMap.put("getLocalId()I", "get_local_id(0)"); - javaToCLIdentifierMap.put("getLocalId(I)I", "get_local_id"); // no parenthesis if we are conveying args - javaToCLIdentifierMap.put("getLocalX()I", "get_local_id(0)"); - javaToCLIdentifierMap.put("getLocalY()I", "get_local_id(1)"); - javaToCLIdentifierMap.put("getLocalZ()I", "get_local_id(2)"); - - javaToCLIdentifierMap.put("getLocalSize()I", "get_local_size(0)"); - javaToCLIdentifierMap.put("getLocalSize(I)I", "get_local_size"); // no parenthesis if we are conveying args - javaToCLIdentifierMap.put("getLocalWidth()I", "get_local_size(0)"); - javaToCLIdentifierMap.put("getLocalHeight()I", "get_local_size(1)"); - javaToCLIdentifierMap.put("getLocalDepth()I", "get_local_size(2)"); - - javaToCLIdentifierMap.put("getNumGroups()I", "get_num_groups(0)"); - javaToCLIdentifierMap.put("getNumGroups(I)I", "get_num_groups"); // no parenthesis if we are conveying args - javaToCLIdentifierMap.put("getNumGroupsX()I", "get_num_groups(0)"); - javaToCLIdentifierMap.put("getNumGroupsY()I", "get_num_groups(1)"); - javaToCLIdentifierMap.put("getNumGroupsZ()I", "get_num_groups(2)"); - - javaToCLIdentifierMap.put("getGroupId()I", "get_group_id(0)"); - javaToCLIdentifierMap.put("getGroupId(I)I", "get_group_id"); // no parenthesis if we are conveying args - javaToCLIdentifierMap.put("getGroupX()I", "get_group_id(0)"); - javaToCLIdentifierMap.put("getGroupY()I", "get_group_id(1)"); - javaToCLIdentifierMap.put("getGroupZ()I", "get_group_id(2)"); - - javaToCLIdentifierMap.put("getPassId()I", "get_pass_id(this)"); - - javaToCLIdentifierMap.put("localBarrier()V", "barrier(CLK_LOCAL_MEM_FENCE)"); - - javaToCLIdentifierMap.put("globalBarrier()V", "barrier(CLK_GLOBAL_MEM_FENCE)"); - } - - /** - * These three convert functions are here to perform - * any type conversion that may be required between - * Java and OpenCL. - * - * @param _typeDesc - * String in the Java JNI notation, [I, etc - * @return Suitably converted string, "char*", etc - */ - @Override public String convertType(String _typeDesc, boolean useClassModel) { - if (_typeDesc.equals("Z") || _typeDesc.equals("boolean")) { - return (cvtBooleanToChar); - } else if (_typeDesc.equals("[Z") || _typeDesc.equals("boolean[]")) { - return (cvtBooleanArrayToCharStar); - } else if (_typeDesc.equals("B") || _typeDesc.equals("byte")) { - return (cvtByteToChar); - } else if (_typeDesc.equals("[B") || _typeDesc.equals("byte[]")) { - return (cvtByteArrayToCharStar); - } else if (_typeDesc.equals("C") || _typeDesc.equals("char")) { - return (cvtCharToShort); - } else if (_typeDesc.equals("[C") || _typeDesc.equals("char[]")) { - return (cvtCharArrayToShortStar); - } else if (_typeDesc.equals("[I") || _typeDesc.equals("int[]")) { - return (cvtIntArrayToIntStar); - } else if (_typeDesc.equals("[F") || _typeDesc.equals("float[]")) { - return (cvtFloatArrayToFloatStar); - } else if (_typeDesc.equals("[D") || _typeDesc.equals("double[]")) { - return (cvtDoubleArrayToDoubleStar); - } else if (_typeDesc.equals("[J") || _typeDesc.equals("long[]")) { - return (cvtLongArrayToLongStar); - } else if (_typeDesc.equals("[S") || _typeDesc.equals("short[]")) { - return (cvtShortArrayToShortStar); - } - // if we get this far, we haven't matched anything yet - if (useClassModel) { - return (ClassModel.convert(_typeDesc, "", true)); - } else { - return _typeDesc; - } - } - - @Override public void writeMethod(MethodCall _methodCall, MethodEntry _methodEntry) throws CodeGenException { - final int argc = _methodEntry.getStackConsumeCount(); - - final String methodName = _methodEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - final String methodSignature = _methodEntry.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); - - final String barrierAndGetterMappings = javaToCLIdentifierMap.get(methodName + methodSignature); - - if (barrierAndGetterMappings != null) { - // this is one of the OpenCL barrier or size getter methods - // write the mapping and exit - if (argc > 0) { - write(barrierAndGetterMappings); - write("("); - for (int arg = 0; arg < argc; arg++) { - if ((arg != 0)) { - write(", "); - } - writeInstruction(_methodCall.getArg(arg)); - } - write(")"); - } else { - write(barrierAndGetterMappings); - } - } else { - final boolean isSpecial = _methodCall instanceof I_INVOKESPECIAL; - MethodModel m = entryPoint.getCallTarget(_methodEntry, isSpecial); - - FieldEntry getterField = null; - if (m != null && m.isGetter()) { - getterField = m.getAccessorVariableFieldEntry(); - } - if (getterField != null && isThis(_methodCall.getArg(0))) { - String fieldName = getterField.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); - write("this->"); - write(fieldName); - return; - } - boolean noCL = _methodEntry.getOwnerClassModel().getNoCLMethods() - .contains(_methodEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); - if (noCL) { - return; - } - final String intrinsicMapping = Kernel.getMappedMethodName(_methodEntry); - // System.out.println("getMappedMethodName for " + methodName + " returned " + mapping); - boolean isIntrinsic = false; - - if (intrinsicMapping == null) { - assert entryPoint != null : "entryPoint should not be null"; - boolean isMapped = Kernel.isMappedMethod(_methodEntry); - - if (m != null) { - write(m.getName()); - } else { - // Must be a library call like rsqrt - assert isMapped : _methodEntry + " should be mapped method!"; - write(methodName); - isIntrinsic = true; - } - } else { - write(intrinsicMapping); - } - - write("("); - - if ((intrinsicMapping == null) && (_methodCall instanceof VirtualMethodCall) && (!isIntrinsic)) { - - final Instruction i = ((VirtualMethodCall) _methodCall).getInstanceReference(); - - if (i instanceof I_ALOAD_0) { - write("this"); - } else if (i instanceof AccessArrayElement) { - final AccessArrayElement arrayAccess = (AccessArrayElement) ((VirtualMethodCall) _methodCall).getInstanceReference(); - final Instruction refAccess = arrayAccess.getArrayRef(); - //assert refAccess instanceof I_GETFIELD : "ref should come from getfield"; - final String fieldName = ((AccessField) refAccess).getConstantPoolFieldEntry().getNameAndTypeEntry() - .getNameUTF8Entry().getUTF8(); - write(" &(this->" + fieldName); - write("["); - writeInstruction(arrayAccess.getArrayIndex()); - write("])"); - } else { - assert false : "unhandled call from: " + i; - } - } - for (int arg = 0; arg < argc; arg++) { - if (((intrinsicMapping == null) && (_methodCall instanceof VirtualMethodCall) && (!isIntrinsic)) || (arg != 0)) { - write(", "); - } - writeInstruction(_methodCall.getArg(arg)); - } - write(")"); - } - } - - private boolean isThis(Instruction instruction) { - return instruction instanceof I_ALOAD_0; - } - - public void writePragma(String _name, boolean _enable) { - write("#pragma OPENCL EXTENSION " + _name + " : " + (_enable ? "en" : "dis") + "able"); - newLine(); - } - - public final static String __local = "__local"; - - public final static String __global = "__global"; - - public final static String __constant = "__constant"; - - public final static String __private = "__private"; - - public final static String LOCAL_ANNOTATION_NAME = "L" + com.aparapi.Kernel.Local.class.getName().replace('.', '/') + ";"; - - public final static String CONSTANT_ANNOTATION_NAME = "L" + com.aparapi.Kernel.Constant.class.getName().replace('.', '/') - + ";"; - - @Override public void write(Entrypoint _entryPoint) throws CodeGenException { - final List<String> thisStruct = new ArrayList<String>(); - final List<String> argLines = new ArrayList<String>(); - final List<String> assigns = new ArrayList<String>(); - - entryPoint = _entryPoint; - - for (final ClassModelField field : _entryPoint.getReferencedClassModelFields()) { - // Field field = _entryPoint.getClassModel().getField(f.getName()); - final StringBuilder thisStructLine = new StringBuilder(); - final StringBuilder argLine = new StringBuilder(); - final StringBuilder assignLine = new StringBuilder(); - - String signature = field.getDescriptor(); - - boolean isPointer = false; - - int numDimensions = 0; - - // check the suffix - - String type = field.getName().endsWith(Kernel.LOCAL_SUFFIX) ? __local - : (field.getName().endsWith(Kernel.CONSTANT_SUFFIX) ? __constant : __global); - Integer privateMemorySize = null; - try { - privateMemorySize = _entryPoint.getClassModel().getPrivateMemorySize(field.getName()); - } catch (ClassParseException e) { - throw new CodeGenException(e); - } - - if (privateMemorySize != null) { - type = __private; - } - final RuntimeAnnotationsEntry visibleAnnotations = field.getAttributePool().getRuntimeVisibleAnnotationsEntry(); - - if (visibleAnnotations != null) { - for (final AnnotationInfo ai : visibleAnnotations) { - final String typeDescriptor = ai.getTypeDescriptor(); - if (typeDescriptor.equals(LOCAL_ANNOTATION_NAME)) { - type = __local; - } else if (typeDescriptor.equals(CONSTANT_ANNOTATION_NAME)) { - type = __constant; - } - } - } - - String argType = (__private.equals(type)) ? __constant : type; - - //if we have a an array we want to mark the object as a pointer - //if we have a multiple dimensional array we want to remember the number of dimensions - while (signature.startsWith("[")) { - if (isPointer == false) { - argLine.append(argType + " "); - if (!(type.equals(__private) && IMPLICIT_PRIVATE_FIELDS)) { - thisStructLine.append(type + " "); - } - } - isPointer = true; - numDimensions++; - signature = signature.substring(1); - } - - // If it is a converted array of objects, emit the struct param - String className = null; - if (signature.startsWith("L")) { - // Turn Lcom/aparapi/javalabs/opencl/demo/DummyOOA; into com_amd_javalabs_opencl_demo_DummyOOA for example - className = (signature.substring(1, signature.length() - 1)).replace('/', '_'); - // if (logger.isLoggable(Level.FINE)) { - // logger.fine("Examining object parameter: " + signature + " new: " + className); - // } - argLine.append(className); - thisStructLine.append(className); - } else { - argLine.append(convertType(ClassModel.typeName(signature.charAt(0)), false)); - thisStructLine.append(convertType(ClassModel.typeName(signature.charAt(0)), false)); - } - - argLine.append(" "); - thisStructLine.append(" "); - - if (isPointer) { - argLine.append("*"); - if (privateMemorySize == null) { - thisStructLine.append("*"); - } - } - - if (privateMemorySize == null) { - assignLine.append("this->"); - assignLine.append(field.getName()); - assignLine.append(" = "); - assignLine.append(field.getName()); - } - - argLine.append(field.getName()); - thisStructLine.append(field.getName()); - if (privateMemorySize == null) { - assigns.add(assignLine.toString()); - } - argLines.add(argLine.toString()); - if (privateMemorySize != null) { - thisStructLine.append("[").append(privateMemorySize).append("]"); - } - thisStruct.add(thisStructLine.toString()); - - // Add int field into "this" struct for supporting java arraylength op - // named like foo__javaArrayLength - if (isPointer && _entryPoint.getArrayFieldArrayLengthUsed().contains(field.getName()) || isPointer && numDimensions > 1) { - - for (int i = 0; i < numDimensions; i++) { - final StringBuilder lenStructLine = new StringBuilder(); - final StringBuilder lenArgLine = new StringBuilder(); - final StringBuilder lenAssignLine = new StringBuilder(); - - String suffix = numDimensions == 1 ? "" : Integer.toString(i); - String lenName = field.getName() + BlockWriter.arrayLengthMangleSuffix + suffix; - - lenStructLine.append("int " + lenName); - - lenAssignLine.append("this->"); - lenAssignLine.append(lenName); - lenAssignLine.append(" = "); - lenAssignLine.append(lenName); - - lenArgLine.append("int " + lenName); - - assigns.add(lenAssignLine.toString()); - argLines.add(lenArgLine.toString()); - thisStruct.add(lenStructLine.toString()); - - if (numDimensions > 1) { - final StringBuilder dimStructLine = new StringBuilder(); - final StringBuilder dimArgLine = new StringBuilder(); - final StringBuilder dimAssignLine = new StringBuilder(); - String dimName = field.getName() + BlockWriter.arrayDimMangleSuffix + suffix; - - dimStructLine.append("int " + dimName); - - dimAssignLine.append("this->"); - dimAssignLine.append(dimName); - dimAssignLine.append(" = "); - dimAssignLine.append(dimName); - - dimArgLine.append("int " + dimName); - - assigns.add(dimAssignLine.toString()); - argLines.add(dimArgLine.toString()); - thisStruct.add(dimStructLine.toString()); - } - } - } - } - - if (Config.enableByteWrites || _entryPoint.requiresByteAddressableStorePragma()) { - // Starting with OpenCL 1.1 (which is as far back as we support) - // this feature is part of the core, so we no longer need this pragma - if (false) { - writePragma("cl_khr_byte_addressable_store", true); - newLine(); - } - } - - boolean usesAtomics = false; - if (Config.enableAtomic32 || _entryPoint.requiresAtomic32Pragma()) { - usesAtomics = true; - writePragma("cl_khr_global_int32_base_atomics", true); - writePragma("cl_khr_global_int32_extended_atomics", true); - writePragma("cl_khr_local_int32_base_atomics", true); - writePragma("cl_khr_local_int32_extended_atomics", true); - } - - if (Config.enableAtomic64 || _entryPoint.requiresAtomic64Pragma()) { - usesAtomics = true; - writePragma("cl_khr_int64_base_atomics", true); - writePragma("cl_khr_int64_extended_atomics", true); - } - - if (usesAtomics) { - write("int atomicAdd(__global int *_arr, int _index, int _delta){"); - in(); - { - newLine(); - write("return atomic_add(&_arr[_index], _delta);"); - out(); - newLine(); - } - write("}"); - - newLine(); - } - - if (Config.enableDoubles || _entryPoint.requiresDoublePragma()) { - writePragma("cl_khr_fp64", true); - newLine(); - } - - // Emit structs for oop transformation accessors - for (final ClassModel cm : _entryPoint.getObjectArrayFieldsClasses().values()) { - final ArrayList<FieldEntry> fieldSet = cm.getStructMembers(); - if (fieldSet.size() > 0) { - final String mangledClassName = cm.getClassWeAreModelling().getName().replace('.', '_'); - newLine(); - write("typedef struct " + mangledClassName + "_s{"); - in(); - newLine(); - - int totalSize = 0; - int alignTo = 0; - - final Iterator<FieldEntry> it = fieldSet.iterator(); - while (it.hasNext()) { - final FieldEntry field = it.next(); - final String fType = field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); - final int fSize = InstructionSet.TypeSpec.valueOf(fType.equals("Z") ? "B" : fType).getSize(); - - if (fSize > alignTo) { - alignTo = fSize; - } - totalSize += fSize; - - final String cType = convertType(field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(), true); - assert cType != null : "could not find type for " + field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); - writeln(cType + " " + field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8() + ";"); - } - - // compute total size for OpenCL buffer - int totalStructSize = 0; - if ((totalSize % alignTo) == 0) { - totalStructSize = totalSize; - } else { - // Pad up if necessary - totalStructSize = ((totalSize / alignTo) + 1) * alignTo; - } - if (totalStructSize > alignTo) { - while (totalSize < totalStructSize) { - // structBuffer.put((byte)-1); - writeln("char _pad_" + totalSize + ";"); - totalSize++; - } - } - - out(); - newLine(); - write("} " + mangledClassName + ";"); - newLine(); - } - } - - write("typedef struct This_s{"); - - in(); - newLine(); - for (final String line : thisStruct) { - write(line); - writeln(";"); - } - write("int passid"); - out(); - writeln(";"); - // out(); - // newLine(); - write("}This;"); - newLine(); - write("int get_pass_id(This *this){"); - in(); - { - newLine(); - write("return this->passid;"); - out(); - newLine(); - } - write("}"); - newLine(); - - for (final MethodModel mm : _entryPoint.getCalledMethods()) { - // write declaration :) - if (mm.isPrivateMemoryGetter()) { - continue; - } - - final String returnType = mm.getReturnType(); - // Arrays always map to __private or__global arrays - if (returnType.startsWith("[")) { - write(" __global "); - } - write(convertType(returnType, true)); - - write(mm.getName() + "("); - - if (!mm.getMethod().isStatic()) { - if ((mm.getMethod().getClassModel() == _entryPoint.getClassModel()) - || mm.getMethod().getClassModel().isSuperClass(_entryPoint.getClassModel().getClassWeAreModelling())) { - write("This *this"); - } else { - // Call to an object member or superclass of member - for (final ClassModel c : _entryPoint.getObjectArrayFieldsClasses().values()) { - if (mm.getMethod().getClassModel() == c) { - write("__global " + mm.getMethod().getClassModel().getClassWeAreModelling().getName().replace('.', '_') - + " *this"); - break; - } else if (mm.getMethod().getClassModel().isSuperClass(c.getClassWeAreModelling())) { - write("__global " + c.getClassWeAreModelling().getName().replace('.', '_') + " *this"); - break; - } - } - } - } - - boolean alreadyHasFirstArg = !mm.getMethod().isStatic(); - - final LocalVariableTableEntry<LocalVariableInfo> lvte = mm.getLocalVariableTableEntry(); - for (final LocalVariableInfo lvi : lvte) { - if ((lvi.getStart() == 0) && ((lvi.getVariableIndex() != 0) || mm.getMethod().isStatic())) { // full scope but skip this - final String descriptor = lvi.getVariableDescriptor(); - if (alreadyHasFirstArg) { - write(", "); - } - - // Arrays always map to __global arrays - if (descriptor.startsWith("[")) { - write(" __global "); - } - - write(convertType(descriptor, true)); - write(lvi.getVariableName()); - alreadyHasFirstArg = true; - } - } - write(")"); - writeMethodBody(mm); - newLine(); - } - - write("__kernel void " + _entryPoint.getMethodModel().getSimpleName() + "("); - - in(); - boolean first = true; - for (final String line : argLines) { - - if (first) { - first = false; - } else { - write(", "); - } - - newLine(); - write(line); - } - - if (first) { - first = false; - } else { - write(", "); - } - newLine(); - write("int passid"); - out(); - newLine(); - write("){"); - in(); - newLine(); - writeln("This thisStruct;"); - writeln("This* this=&thisStruct;"); - for (final String line : assigns) { - write(line); - writeln(";"); - } - write("this->passid = passid"); - writeln(";"); - - writeMethodBody(_entryPoint.getMethodModel()); - out(); - newLine(); - writeln("}"); - out(); - } - - @Override public void writeThisRef() { - write("this->"); - } - - @Override public void writeInstruction(Instruction _instruction) throws CodeGenException { - if ((_instruction instanceof I_IUSHR) || (_instruction instanceof I_LUSHR)) { - final BinaryOperator binaryInstruction = (BinaryOperator) _instruction; - final Instruction parent = binaryInstruction.getParentExpr(); - boolean needsParenthesis = true; - - if (parent instanceof AssignToLocalVariable) { - needsParenthesis = false; - } else if (parent instanceof AssignToField) { - needsParenthesis = false; - } else if (parent instanceof AssignToArrayElement) { - needsParenthesis = false; - } - if (needsParenthesis) { - write("("); - } - - if (binaryInstruction instanceof I_IUSHR) { - write("((unsigned int)"); - } else { - write("((unsigned long)"); - } - writeInstruction(binaryInstruction.getLhs()); - write(")"); - write(" >> "); - writeInstruction(binaryInstruction.getRhs()); - - if (needsParenthesis) { - write(")"); - } - } else { - super.writeInstruction(_instruction); - } - } - - public static String writeToString(Entrypoint _entrypoint) throws CodeGenException { - final StringBuilder openCLStringBuilder = new StringBuilder(); - final KernelWriter openCLWriter = new KernelWriter(){ - @Override public void write(String _string) { - openCLStringBuilder.append(_string); - } - }; - try { - openCLWriter.write(_entrypoint); - } catch (final CodeGenException codeGenException) { - throw codeGenException; - }/* catch (final Throwable t) { - throw new CodeGenException(t); - }*/ - - return (openCLStringBuilder.toString()); - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + + */ +package com.aparapi.internal.writer; + +import com.aparapi.*; +import com.aparapi.internal.exception.*; +import com.aparapi.internal.instruction.*; +import com.aparapi.internal.instruction.InstructionSet.*; +import com.aparapi.internal.model.*; +import com.aparapi.internal.model.ClassModel.AttributePool.*; +import com.aparapi.internal.model.ClassModel.AttributePool.RuntimeAnnotationsEntry.*; +import com.aparapi.internal.model.ClassModel.*; +import com.aparapi.internal.model.ClassModel.ConstantPool.*; + +import java.util.*; + +public abstract class KernelWriter extends BlockWriter{ + + private final String cvtBooleanToChar = "char "; + + private final String cvtBooleanArrayToCharStar = "char* "; + + private final String cvtByteToChar = "char "; + + private final String cvtByteArrayToCharStar = "char* "; + + private final String cvtCharToShort = "unsigned short "; + + private final String cvtCharArrayToShortStar = "unsigned short* "; + + private final String cvtIntArrayToIntStar = "int* "; + + private final String cvtFloatArrayToFloatStar = "float* "; + + private final String cvtDoubleArrayToDoubleStar = "double* "; + + private final String cvtLongArrayToLongStar = "long* "; + + private final String cvtShortArrayToShortStar = "short* "; + + /** When declaring a __private struct pointer field, we always omit the "__private" qualifier. This is because the NVidia OpenCL compiler, at time of writing + * erroneously complains about explicitly qualifying pointers with __private ("error: field may not be qualified with an address space"). + */ + private static final boolean IMPLICIT_PRIVATE_FIELDS = true; + + // private static Logger logger = Logger.getLogger(Config.getLoggerName()); + + private Entrypoint entryPoint = null; + + public final static Map<String, String> javaToCLIdentifierMap = new HashMap<String, String>(); + { + javaToCLIdentifierMap.put("getGlobalId()I", "get_global_id(0)"); + javaToCLIdentifierMap.put("getGlobalId(I)I", "get_global_id"); // no parenthesis if we are conveying args + javaToCLIdentifierMap.put("getGlobalX()I", "get_global_id(0)"); + javaToCLIdentifierMap.put("getGlobalY()I", "get_global_id(1)"); + javaToCLIdentifierMap.put("getGlobalZ()I", "get_global_id(2)"); + + javaToCLIdentifierMap.put("getGlobalSize()I", "get_global_size(0)"); + javaToCLIdentifierMap.put("getGlobalSize(I)I", "get_global_size"); // no parenthesis if we are conveying args + javaToCLIdentifierMap.put("getGlobalWidth()I", "get_global_size(0)"); + javaToCLIdentifierMap.put("getGlobalHeight()I", "get_global_size(1)"); + javaToCLIdentifierMap.put("getGlobalDepth()I", "get_global_size(2)"); + + javaToCLIdentifierMap.put("getLocalId()I", "get_local_id(0)"); + javaToCLIdentifierMap.put("getLocalId(I)I", "get_local_id"); // no parenthesis if we are conveying args + javaToCLIdentifierMap.put("getLocalX()I", "get_local_id(0)"); + javaToCLIdentifierMap.put("getLocalY()I", "get_local_id(1)"); + javaToCLIdentifierMap.put("getLocalZ()I", "get_local_id(2)"); + + javaToCLIdentifierMap.put("getLocalSize()I", "get_local_size(0)"); + javaToCLIdentifierMap.put("getLocalSize(I)I", "get_local_size"); // no parenthesis if we are conveying args + javaToCLIdentifierMap.put("getLocalWidth()I", "get_local_size(0)"); + javaToCLIdentifierMap.put("getLocalHeight()I", "get_local_size(1)"); + javaToCLIdentifierMap.put("getLocalDepth()I", "get_local_size(2)"); + + javaToCLIdentifierMap.put("getNumGroups()I", "get_num_groups(0)"); + javaToCLIdentifierMap.put("getNumGroups(I)I", "get_num_groups"); // no parenthesis if we are conveying args + javaToCLIdentifierMap.put("getNumGroupsX()I", "get_num_groups(0)"); + javaToCLIdentifierMap.put("getNumGroupsY()I", "get_num_groups(1)"); + javaToCLIdentifierMap.put("getNumGroupsZ()I", "get_num_groups(2)"); + + javaToCLIdentifierMap.put("getGroupId()I", "get_group_id(0)"); + javaToCLIdentifierMap.put("getGroupId(I)I", "get_group_id"); // no parenthesis if we are conveying args + javaToCLIdentifierMap.put("getGroupX()I", "get_group_id(0)"); + javaToCLIdentifierMap.put("getGroupY()I", "get_group_id(1)"); + javaToCLIdentifierMap.put("getGroupZ()I", "get_group_id(2)"); + + javaToCLIdentifierMap.put("getPassId()I", "get_pass_id(this)"); + + javaToCLIdentifierMap.put("localBarrier()V", "barrier(CLK_LOCAL_MEM_FENCE)"); + + javaToCLIdentifierMap.put("globalBarrier()V", "barrier(CLK_GLOBAL_MEM_FENCE)"); + } + + /** + * These three convert functions are here to perform + * any type conversion that may be required between + * Java and OpenCL. + * + * @param _typeDesc + * String in the Java JNI notation, [I, etc + * @return Suitably converted string, "char*", etc + */ + @Override public String convertType(String _typeDesc, boolean useClassModel) { + if (_typeDesc.equals("Z") || _typeDesc.equals("boolean")) { + return (cvtBooleanToChar); + } else if (_typeDesc.equals("[Z") || _typeDesc.equals("boolean[]")) { + return (cvtBooleanArrayToCharStar); + } else if (_typeDesc.equals("B") || _typeDesc.equals("byte")) { + return (cvtByteToChar); + } else if (_typeDesc.equals("[B") || _typeDesc.equals("byte[]")) { + return (cvtByteArrayToCharStar); + } else if (_typeDesc.equals("C") || _typeDesc.equals("char")) { + return (cvtCharToShort); + } else if (_typeDesc.equals("[C") || _typeDesc.equals("char[]")) { + return (cvtCharArrayToShortStar); + } else if (_typeDesc.equals("[I") || _typeDesc.equals("int[]")) { + return (cvtIntArrayToIntStar); + } else if (_typeDesc.equals("[F") || _typeDesc.equals("float[]")) { + return (cvtFloatArrayToFloatStar); + } else if (_typeDesc.equals("[D") || _typeDesc.equals("double[]")) { + return (cvtDoubleArrayToDoubleStar); + } else if (_typeDesc.equals("[J") || _typeDesc.equals("long[]")) { + return (cvtLongArrayToLongStar); + } else if (_typeDesc.equals("[S") || _typeDesc.equals("short[]")) { + return (cvtShortArrayToShortStar); + } + // if we get this far, we haven't matched anything yet + if (useClassModel) { + return (ClassModel.convert(_typeDesc, "", true)); + } else { + return _typeDesc; + } + } + + @Override public void writeMethod(MethodCall _methodCall, MethodEntry _methodEntry) throws CodeGenException { + final int argc = _methodEntry.getStackConsumeCount(); + + final String methodName = _methodEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + final String methodSignature = _methodEntry.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); + + final String barrierAndGetterMappings = javaToCLIdentifierMap.get(methodName + methodSignature); + + if (barrierAndGetterMappings != null) { + // this is one of the OpenCL barrier or size getter methods + // write the mapping and exit + if (argc > 0) { + write(barrierAndGetterMappings); + write("("); + for (int arg = 0; arg < argc; arg++) { + if ((arg != 0)) { + write(", "); + } + writeInstruction(_methodCall.getArg(arg)); + } + write(")"); + } else { + write(barrierAndGetterMappings); + } + } else { + final boolean isSpecial = _methodCall instanceof I_INVOKESPECIAL; + MethodModel m = entryPoint.getCallTarget(_methodEntry, isSpecial); + + FieldEntry getterField = null; + if (m != null && m.isGetter()) { + getterField = m.getAccessorVariableFieldEntry(); + } + if (getterField != null && isThis(_methodCall.getArg(0))) { + String fieldName = getterField.getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); + write("this->"); + write(fieldName); + return; + } + boolean noCL = _methodEntry.getOwnerClassModel().getNoCLMethods() + .contains(_methodEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8()); + if (noCL) { + return; + } + final String intrinsicMapping = Kernel.getMappedMethodName(_methodEntry); + // System.out.println("getMappedMethodName for " + methodName + " returned " + mapping); + boolean isIntrinsic = false; + + if (intrinsicMapping == null) { + assert entryPoint != null : "entryPoint should not be null"; + boolean isMapped = Kernel.isMappedMethod(_methodEntry); + + if (m != null) { + write(m.getName()); + } else { + // Must be a library call like rsqrt + assert isMapped : _methodEntry + " should be mapped method!"; + write(methodName); + isIntrinsic = true; + } + } else { + write(intrinsicMapping); + } + + write("("); + + if ((intrinsicMapping == null) && (_methodCall instanceof VirtualMethodCall) && (!isIntrinsic)) { + + final Instruction i = ((VirtualMethodCall) _methodCall).getInstanceReference(); + + if (i instanceof I_ALOAD_0) { + write("this"); + } else if (i instanceof AccessArrayElement) { + final AccessArrayElement arrayAccess = (AccessArrayElement) ((VirtualMethodCall) _methodCall).getInstanceReference(); + final Instruction refAccess = arrayAccess.getArrayRef(); + //assert refAccess instanceof I_GETFIELD : "ref should come from getfield"; + final String fieldName = ((AccessField) refAccess).getConstantPoolFieldEntry().getNameAndTypeEntry() + .getNameUTF8Entry().getUTF8(); + write(" &(this->" + fieldName); + write("["); + writeInstruction(arrayAccess.getArrayIndex()); + write("])"); + } else { + assert false : "unhandled call from: " + i; + } + } + for (int arg = 0; arg < argc; arg++) { + if (((intrinsicMapping == null) && (_methodCall instanceof VirtualMethodCall) && (!isIntrinsic)) || (arg != 0)) { + write(", "); + } + writeInstruction(_methodCall.getArg(arg)); + } + write(")"); + } + } + + private boolean isThis(Instruction instruction) { + return instruction instanceof I_ALOAD_0; + } + + public void writePragma(String _name, boolean _enable) { + write("#pragma OPENCL EXTENSION " + _name + " : " + (_enable ? "en" : "dis") + "able"); + newLine(); + } + + public final static String __local = "__local"; + + public final static String __global = "__global"; + + public final static String __constant = "__constant"; + + public final static String __private = "__private"; + + public final static String LOCAL_ANNOTATION_NAME = "L" + com.aparapi.Kernel.Local.class.getName().replace('.', '/') + ";"; + + public final static String CONSTANT_ANNOTATION_NAME = "L" + com.aparapi.Kernel.Constant.class.getName().replace('.', '/') + + ";"; + + @Override public void write(Entrypoint _entryPoint) throws CodeGenException { + final List<String> thisStruct = new ArrayList<String>(); + final List<String> argLines = new ArrayList<String>(); + final List<String> assigns = new ArrayList<String>(); + + entryPoint = _entryPoint; + + for (final ClassModelField field : _entryPoint.getReferencedClassModelFields()) { + // Field field = _entryPoint.getClassModel().getField(f.getName()); + final StringBuilder thisStructLine = new StringBuilder(); + final StringBuilder argLine = new StringBuilder(); + final StringBuilder assignLine = new StringBuilder(); + + String signature = field.getDescriptor(); + + boolean isPointer = false; + + int numDimensions = 0; + + // check the suffix + + String type = field.getName().endsWith(Kernel.LOCAL_SUFFIX) ? __local + : (field.getName().endsWith(Kernel.CONSTANT_SUFFIX) ? __constant : __global); + Integer privateMemorySize = null; + try { + privateMemorySize = _entryPoint.getClassModel().getPrivateMemorySize(field.getName()); + } catch (ClassParseException e) { + throw new CodeGenException(e); + } + + if (privateMemorySize != null) { + type = __private; + } + final RuntimeAnnotationsEntry visibleAnnotations = field.getAttributePool().getRuntimeVisibleAnnotationsEntry(); + + if (visibleAnnotations != null) { + for (final AnnotationInfo ai : visibleAnnotations) { + final String typeDescriptor = ai.getTypeDescriptor(); + if (typeDescriptor.equals(LOCAL_ANNOTATION_NAME)) { + type = __local; + } else if (typeDescriptor.equals(CONSTANT_ANNOTATION_NAME)) { + type = __constant; + } + } + } + + String argType = (__private.equals(type)) ? __constant : type; + + //if we have a an array we want to mark the object as a pointer + //if we have a multiple dimensional array we want to remember the number of dimensions + while (signature.startsWith("[")) { + if (isPointer == false) { + argLine.append(argType + " "); + if (!(type.equals(__private) && IMPLICIT_PRIVATE_FIELDS)) { + thisStructLine.append(type + " "); + } + } + isPointer = true; + numDimensions++; + signature = signature.substring(1); + } + + // If it is a converted array of objects, emit the struct param + String className = null; + if (signature.startsWith("L")) { + // Turn Lcom/aparapi/javalabs/opencl/demo/DummyOOA; into com_amd_javalabs_opencl_demo_DummyOOA for example + className = (signature.substring(1, signature.length() - 1)).replace('/', '_'); + // if (logger.isLoggable(Level.FINE)) { + // logger.fine("Examining object parameter: " + signature + " new: " + className); + // } + argLine.append(className); + thisStructLine.append(className); + } else { + argLine.append(convertType(ClassModel.typeName(signature.charAt(0)), false)); + thisStructLine.append(convertType(ClassModel.typeName(signature.charAt(0)), false)); + } + + argLine.append(" "); + thisStructLine.append(" "); + + if (isPointer) { + argLine.append("*"); + if (privateMemorySize == null) { + thisStructLine.append("*"); + } + } + + if (privateMemorySize == null) { + assignLine.append("this->"); + assignLine.append(field.getName()); + assignLine.append(" = "); + assignLine.append(field.getName()); + } + + argLine.append(field.getName()); + thisStructLine.append(field.getName()); + if (privateMemorySize == null) { + assigns.add(assignLine.toString()); + } + argLines.add(argLine.toString()); + if (privateMemorySize != null) { + thisStructLine.append("[").append(privateMemorySize).append("]"); + } + thisStruct.add(thisStructLine.toString()); + + // Add int field into "this" struct for supporting java arraylength op + // named like foo__javaArrayLength + if (isPointer && _entryPoint.getArrayFieldArrayLengthUsed().contains(field.getName()) || isPointer && numDimensions > 1) { + + for (int i = 0; i < numDimensions; i++) { + final StringBuilder lenStructLine = new StringBuilder(); + final StringBuilder lenArgLine = new StringBuilder(); + final StringBuilder lenAssignLine = new StringBuilder(); + + String suffix = numDimensions == 1 ? "" : Integer.toString(i); + String lenName = field.getName() + BlockWriter.arrayLengthMangleSuffix + suffix; + + lenStructLine.append("int " + lenName); + + lenAssignLine.append("this->"); + lenAssignLine.append(lenName); + lenAssignLine.append(" = "); + lenAssignLine.append(lenName); + + lenArgLine.append("int " + lenName); + + assigns.add(lenAssignLine.toString()); + argLines.add(lenArgLine.toString()); + thisStruct.add(lenStructLine.toString()); + + if (numDimensions > 1) { + final StringBuilder dimStructLine = new StringBuilder(); + final StringBuilder dimArgLine = new StringBuilder(); + final StringBuilder dimAssignLine = new StringBuilder(); + String dimName = field.getName() + BlockWriter.arrayDimMangleSuffix + suffix; + + dimStructLine.append("int " + dimName); + + dimAssignLine.append("this->"); + dimAssignLine.append(dimName); + dimAssignLine.append(" = "); + dimAssignLine.append(dimName); + + dimArgLine.append("int " + dimName); + + assigns.add(dimAssignLine.toString()); + argLines.add(dimArgLine.toString()); + thisStruct.add(dimStructLine.toString()); + } + } + } + } + + if (Config.enableByteWrites || _entryPoint.requiresByteAddressableStorePragma()) { + // Starting with OpenCL 1.1 (which is as far back as we support) + // this feature is part of the core, so we no longer need this pragma + if (false) { + writePragma("cl_khr_byte_addressable_store", true); + newLine(); + } + } + + boolean usesAtomics = false; + if (Config.enableAtomic32 || _entryPoint.requiresAtomic32Pragma()) { + usesAtomics = true; + writePragma("cl_khr_global_int32_base_atomics", true); + writePragma("cl_khr_global_int32_extended_atomics", true); + writePragma("cl_khr_local_int32_base_atomics", true); + writePragma("cl_khr_local_int32_extended_atomics", true); + } + + if (Config.enableAtomic64 || _entryPoint.requiresAtomic64Pragma()) { + usesAtomics = true; + writePragma("cl_khr_int64_base_atomics", true); + writePragma("cl_khr_int64_extended_atomics", true); + } + + if (usesAtomics) { + write("int atomicAdd(__global int *_arr, int _index, int _delta){"); + in(); + { + newLine(); + write("return atomic_add(&_arr[_index], _delta);"); + out(); + newLine(); + } + write("}"); + + newLine(); + } + + if (Config.enableDoubles || _entryPoint.requiresDoublePragma()) { + writePragma("cl_khr_fp64", true); + newLine(); + } + + // Emit structs for oop transformation accessors + for (final ClassModel cm : _entryPoint.getObjectArrayFieldsClasses().values()) { + final ArrayList<FieldEntry> fieldSet = cm.getStructMembers(); + if (fieldSet.size() > 0) { + final String mangledClassName = cm.getClassWeAreModelling().getName().replace('.', '_'); + newLine(); + write("typedef struct " + mangledClassName + "_s{"); + in(); + newLine(); + + int totalSize = 0; + int alignTo = 0; + + final Iterator<FieldEntry> it = fieldSet.iterator(); + while (it.hasNext()) { + final FieldEntry field = it.next(); + final String fType = field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); + final int fSize = InstructionSet.TypeSpec.valueOf(fType.equals("Z") ? "B" : fType).getSize(); + + if (fSize > alignTo) { + alignTo = fSize; + } + totalSize += fSize; + + final String cType = convertType(field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(), true); + assert cType != null : "could not find type for " + field.getNameAndTypeEntry().getDescriptorUTF8Entry().getUTF8(); + writeln(cType + " " + field.getNameAndTypeEntry().getNameUTF8Entry().getUTF8() + ";"); + } + + // compute total size for OpenCL buffer + int totalStructSize = 0; + if ((totalSize % alignTo) == 0) { + totalStructSize = totalSize; + } else { + // Pad up if necessary + totalStructSize = ((totalSize / alignTo) + 1) * alignTo; + } + if (totalStructSize > alignTo) { + while (totalSize < totalStructSize) { + // structBuffer.put((byte)-1); + writeln("char _pad_" + totalSize + ";"); + totalSize++; + } + } + + out(); + newLine(); + write("} " + mangledClassName + ";"); + newLine(); + } + } + + write("typedef struct This_s{"); + + in(); + newLine(); + for (final String line : thisStruct) { + write(line); + writeln(";"); + } + write("int passid"); + out(); + writeln(";"); + // out(); + // newLine(); + write("}This;"); + newLine(); + write("int get_pass_id(This *this){"); + in(); + { + newLine(); + write("return this->passid;"); + out(); + newLine(); + } + write("}"); + newLine(); + + for (final MethodModel mm : _entryPoint.getCalledMethods()) { + // write declaration :) + if (mm.isPrivateMemoryGetter()) { + continue; + } + + final String returnType = mm.getReturnType(); + // Arrays always map to __private or__global arrays + if (returnType.startsWith("[")) { + write(" __global "); + } + write(convertType(returnType, true)); + + write(mm.getName() + "("); + + if (!mm.getMethod().isStatic()) { + if ((mm.getMethod().getClassModel() == _entryPoint.getClassModel()) + || mm.getMethod().getClassModel().isSuperClass(_entryPoint.getClassModel().getClassWeAreModelling())) { + write("This *this"); + } else { + // Call to an object member or superclass of member + for (final ClassModel c : _entryPoint.getObjectArrayFieldsClasses().values()) { + if (mm.getMethod().getClassModel() == c) { + write("__global " + mm.getMethod().getClassModel().getClassWeAreModelling().getName().replace('.', '_') + + " *this"); + break; + } else if (mm.getMethod().getClassModel().isSuperClass(c.getClassWeAreModelling())) { + write("__global " + c.getClassWeAreModelling().getName().replace('.', '_') + " *this"); + break; + } + } + } + } + + boolean alreadyHasFirstArg = !mm.getMethod().isStatic(); + + final LocalVariableTableEntry<LocalVariableInfo> lvte = mm.getLocalVariableTableEntry(); + for (final LocalVariableInfo lvi : lvte) { + if ((lvi.getStart() == 0) && ((lvi.getVariableIndex() != 0) || mm.getMethod().isStatic())) { // full scope but skip this + final String descriptor = lvi.getVariableDescriptor(); + if (alreadyHasFirstArg) { + write(", "); + } + + // Arrays always map to __global arrays + if (descriptor.startsWith("[")) { + write(" __global "); + } + + write(convertType(descriptor, true)); + write(lvi.getVariableName()); + alreadyHasFirstArg = true; + } + } + write(")"); + writeMethodBody(mm); + newLine(); + } + + write("__kernel void " + _entryPoint.getMethodModel().getSimpleName() + "("); + + in(); + boolean first = true; + for (final String line : argLines) { + + if (first) { + first = false; + } else { + write(", "); + } + + newLine(); + write(line); + } + + if (first) { + first = false; + } else { + write(", "); + } + newLine(); + write("int passid"); + out(); + newLine(); + write("){"); + in(); + newLine(); + writeln("This thisStruct;"); + writeln("This* this=&thisStruct;"); + for (final String line : assigns) { + write(line); + writeln(";"); + } + write("this->passid = passid"); + writeln(";"); + + writeMethodBody(_entryPoint.getMethodModel()); + out(); + newLine(); + writeln("}"); + out(); + } + + @Override public void writeThisRef() { + write("this->"); + } + + @Override public void writeInstruction(Instruction _instruction) throws CodeGenException { + if ((_instruction instanceof I_IUSHR) || (_instruction instanceof I_LUSHR)) { + final BinaryOperator binaryInstruction = (BinaryOperator) _instruction; + final Instruction parent = binaryInstruction.getParentExpr(); + boolean needsParenthesis = true; + + if (parent instanceof AssignToLocalVariable) { + needsParenthesis = false; + } else if (parent instanceof AssignToField) { + needsParenthesis = false; + } else if (parent instanceof AssignToArrayElement) { + needsParenthesis = false; + } + if (needsParenthesis) { + write("("); + } + + if (binaryInstruction instanceof I_IUSHR) { + write("((unsigned int)"); + } else { + write("((unsigned long)"); + } + writeInstruction(binaryInstruction.getLhs()); + write(")"); + write(" >> "); + writeInstruction(binaryInstruction.getRhs()); + + if (needsParenthesis) { + write(")"); + } + } else { + super.writeInstruction(_instruction); + } + } + + public static String writeToString(Entrypoint _entrypoint) throws CodeGenException { + final StringBuilder openCLStringBuilder = new StringBuilder(); + final KernelWriter openCLWriter = new KernelWriter(){ + @Override public void write(String _string) { + openCLStringBuilder.append(_string); + } + }; + try { + openCLWriter.write(_entrypoint); + } catch (final CodeGenException codeGenException) { + throw codeGenException; + }/* catch (final Throwable t) { + throw new CodeGenException(t); + }*/ + + return (openCLStringBuilder.toString()); + } +} diff --git a/src/main/java/com/aparapi/opencl/OpenCL.java b/src/main/java/com/aparapi/opencl/OpenCL.java index f15e0d2a0b1db8f48de6d1e23dfba27960f2b2dd..dd21a2788614b8869920aeabf442fda5937afdc5 100644 --- a/src/main/java/com/aparapi/opencl/OpenCL.java +++ b/src/main/java/com/aparapi/opencl/OpenCL.java @@ -1,128 +1,128 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.opencl; - -import com.aparapi.ProfileInfo; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.List; - -public interface OpenCL<T> { - - public static final String CL_KHR_FP64 = "cl_khr_fp64"; - - public static final String CL_KHR_SELECT_FPROUNDING_MODE = "cl_khr_select_fprounding_mode"; - - public static final String CL_KHR_GLOBAL_INT32_BASE_ATOMICS = "cl_khr_global_int32_base_atomics"; - - public static final String CL_KHR_GLOBAL_INT32_EXTENDED_ATOMICS = "cl_khr_global_int32_extended_atomics"; - - public static final String CL_KHR_LOCAL_INT32_BASE_ATOMICS = "cl_khr_local_int32_base_atomics"; - - public static final String CL_KHR_LOCAL_INT32_EXTENDED_ATOMICS = "cl_khr_local_int32_extended_atomics"; - - public static final String CL_KHR_INT64_BASE_ATOMICS = "cl_khr_int64_base_atomics"; - - public static final String CL_KHR_INT64_EXTENDED_ATOMICS = "cl_khr_int64_extended_atomics"; - - public static final String CL_KHR_3D_IMAGE_WRITES = "cl_khr_3d_image_writes"; - - public static final String CL_KHR_BYTE_ADDRESSABLE_SUPPORT = "cl_khr_byte_addressable_store"; - - public static final String CL_KHR_FP16 = "cl_khr_fp16"; - - public static final String CL_KHR_GL_SHARING = "cl_khr_gl_sharing"; - - @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Put { - } - - @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Get { - } - - @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Source { - String value(); - } - - @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Resource { - String value(); - } - - @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Kernel { - String value(); - } - - @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Arg { - String value(); - } - - @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface GlobalReadWrite { - String value(); - } - - @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface GlobalReadOnly { - String value(); - } - - @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface GlobalWriteOnly { - String value(); - } - - @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Local { - String value(); - } - - @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Constant { - String value(); - } - - public T put(float[] array); - - public T put(int[] array); - - public T put(short[] array); - - public T put(byte[] array); - - public T put(char[] array); - - public T put(boolean[] array); - - public T put(double[] array); - - public T get(float[] array); - - public T get(int[] array); - - public T get(short[] array); - - public T get(char[] array); - - public T get(boolean[] array); - - public T get(double[] array); - - public T get(byte[] array); - - public T begin(); - - public T end(); - - public T dispose(); - - public List<ProfileInfo> getProfileInfo(); -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.opencl; + +import com.aparapi.ProfileInfo; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; + +public interface OpenCL<T> { + + public static final String CL_KHR_FP64 = "cl_khr_fp64"; + + public static final String CL_KHR_SELECT_FPROUNDING_MODE = "cl_khr_select_fprounding_mode"; + + public static final String CL_KHR_GLOBAL_INT32_BASE_ATOMICS = "cl_khr_global_int32_base_atomics"; + + public static final String CL_KHR_GLOBAL_INT32_EXTENDED_ATOMICS = "cl_khr_global_int32_extended_atomics"; + + public static final String CL_KHR_LOCAL_INT32_BASE_ATOMICS = "cl_khr_local_int32_base_atomics"; + + public static final String CL_KHR_LOCAL_INT32_EXTENDED_ATOMICS = "cl_khr_local_int32_extended_atomics"; + + public static final String CL_KHR_INT64_BASE_ATOMICS = "cl_khr_int64_base_atomics"; + + public static final String CL_KHR_INT64_EXTENDED_ATOMICS = "cl_khr_int64_extended_atomics"; + + public static final String CL_KHR_3D_IMAGE_WRITES = "cl_khr_3d_image_writes"; + + public static final String CL_KHR_BYTE_ADDRESSABLE_SUPPORT = "cl_khr_byte_addressable_store"; + + public static final String CL_KHR_FP16 = "cl_khr_fp16"; + + public static final String CL_KHR_GL_SHARING = "cl_khr_gl_sharing"; + + @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Put { + } + + @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Get { + } + + @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Source { + String value(); + } + + @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Resource { + String value(); + } + + @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Kernel { + String value(); + } + + @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Arg { + String value(); + } + + @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface GlobalReadWrite { + String value(); + } + + @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface GlobalReadOnly { + String value(); + } + + @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface GlobalWriteOnly { + String value(); + } + + @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Local { + String value(); + } + + @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Constant { + String value(); + } + + public T put(float[] array); + + public T put(int[] array); + + public T put(short[] array); + + public T put(byte[] array); + + public T put(char[] array); + + public T put(boolean[] array); + + public T put(double[] array); + + public T get(float[] array); + + public T get(int[] array); + + public T get(short[] array); + + public T get(char[] array); + + public T get(boolean[] array); + + public T get(double[] array); + + public T get(byte[] array); + + public T begin(); + + public T end(); + + public T dispose(); + + public List<ProfileInfo> getProfileInfo(); +} diff --git a/src/main/java/com/aparapi/opencl/OpenCLAdapter.java b/src/main/java/com/aparapi/opencl/OpenCLAdapter.java index 50695c344ca77b891c2e94618b0ab15ce588d3e7..95bb104ff9c614ce4e2f1374f5a793b2203e1b92 100644 --- a/src/main/java/com/aparapi/opencl/OpenCLAdapter.java +++ b/src/main/java/com/aparapi/opencl/OpenCLAdapter.java @@ -1,96 +1,96 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.opencl; - -import com.aparapi.ProfileInfo; -import java.util.ArrayList; -import java.util.List; - -public class OpenCLAdapter<T> implements OpenCL<T>{ - - @SuppressWarnings("unchecked") public T put(byte[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T get(byte[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T put(float[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T put(int[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T put(short[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T put(char[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T put(boolean[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T put(double[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T get(float[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T get(int[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T get(short[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T get(char[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T get(boolean[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T get(double[] array) { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T begin() { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T end() { - return ((T) this); - } - - @SuppressWarnings("unchecked") public T dispose() { - return ((T) this); - } - - public List<ProfileInfo> getProfileInfo(){ - return(new ArrayList<ProfileInfo>()); - } - -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.opencl; + +import com.aparapi.ProfileInfo; +import java.util.ArrayList; +import java.util.List; + +public class OpenCLAdapter<T> implements OpenCL<T>{ + + @SuppressWarnings("unchecked") public T put(byte[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T get(byte[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T put(float[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T put(int[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T put(short[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T put(char[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T put(boolean[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T put(double[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T get(float[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T get(int[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T get(short[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T get(char[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T get(boolean[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T get(double[] array) { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T begin() { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T end() { + return ((T) this); + } + + @SuppressWarnings("unchecked") public T dispose() { + return ((T) this); + } + + public List<ProfileInfo> getProfileInfo(){ + return(new ArrayList<ProfileInfo>()); + } + +} diff --git a/src/main/java/com/aparapi/opencl/package-info.java b/src/main/java/com/aparapi/opencl/package-info.java index 3f6ff47ce4adfa89b531239aea3feba35461c8fc..95a4c34de55de964aa86605f0f604d96fe126c23 100644 --- a/src/main/java/com/aparapi/opencl/package-info.java +++ b/src/main/java/com/aparapi/opencl/package-info.java @@ -1,19 +1,19 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * - */ +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + */ package com.aparapi.opencl; \ No newline at end of file diff --git a/src/main/java/com/aparapi/package-info.java b/src/main/java/com/aparapi/package-info.java index 8a4492be69f7da41e69e1c0aaffaeb38dc1aa698..4286c6486f156973a7059bea78635cc40a044973 100644 --- a/src/main/java/com/aparapi/package-info.java +++ b/src/main/java/com/aparapi/package-info.java @@ -1,19 +1,19 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * - */ +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + */ package com.aparapi; \ No newline at end of file diff --git a/src/main/java/com/aparapi/util/swing/MultiPassKernelSwingWorker.java b/src/main/java/com/aparapi/util/swing/MultiPassKernelSwingWorker.java index 96bbafd8a46103f668de70227247d50b0c9a68d7..d9d51c945751762e18ddbef81b046bab767e802e 100644 --- a/src/main/java/com/aparapi/util/swing/MultiPassKernelSwingWorker.java +++ b/src/main/java/com/aparapi/util/swing/MultiPassKernelSwingWorker.java @@ -1,99 +1,99 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.aparapi.util.swing; - -import com.aparapi.Kernel; -import com.aparapi.internal.kernel.KernelRunner; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * Implementation of SwingWorker to assist in progress tracking and cancellation of multi-pass {@link Kernel}s. - */ -public abstract class MultiPassKernelSwingWorker extends SwingWorker<Void, Void>{ - - public static final int DEFAULT_POLL_INTERVAL = 50; - - private Kernel kernel; - private Timer timer; - - protected MultiPassKernelSwingWorker(Kernel kernel) { - this.kernel = kernel; - } - - /** Utility method which just invokes {@link Kernel#cancelMultiPass()} on the executing kernel. */ - public void cancelExecution() { - kernel.cancelMultiPass(); - } - - /** This method must invoke one of the {@code kernel}'s execute() methods. */ - protected abstract void executeKernel(Kernel kernel); - - /** This method, which is always invoked on the swing event dispatch thread, should be used to update any components (such as a {@link javax.swing.JProgressBar}) so - * as to reflect the progress of the multi-pass Kernel being executed. - * - * @param passId The passId for the Kernel's current pass, or one of the constant fields returnable by {@link KernelRunner#getCurrentPass()}. - */ - protected abstract void updatePassId(int passId); - - /** Executes the {@link #kernel} via {@link #executeKernel(Kernel)}, whilst also managing progress updates for the kernel's passId. */ - @Override - protected final Void doInBackground() throws Exception { - try { - setUpExecution(); - executeKernel(kernel); - return null; - } - finally { - cleanUpExecution(); - } - } - - private void setUpExecution() { - ActionListener listener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatePassId(); - } - }; - timer = new Timer(getPollIntervalMillis(), listener); - timer.setCoalesce(false); - timer.start(); - } - - private void cleanUpExecution() { - timer.stop(); - timer = null; - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - updatePassId(KernelRunner.PASS_ID_COMPLETED_EXECUTION); - } - }); - } - - private void updatePassId() { - int progress = kernel.getCurrentPass(); - updatePassId(progress); - } - - /** The interval at which the Kernel's current passId is polled. Unless overridden, returns {@link #DEFAULT_POLL_INTERVAL}. */ - protected int getPollIntervalMillis() { - return DEFAULT_POLL_INTERVAL; - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.util.swing; + +import com.aparapi.Kernel; +import com.aparapi.internal.kernel.KernelRunner; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Implementation of SwingWorker to assist in progress tracking and cancellation of multi-pass {@link Kernel}s. + */ +public abstract class MultiPassKernelSwingWorker extends SwingWorker<Void, Void>{ + + public static final int DEFAULT_POLL_INTERVAL = 50; + + private Kernel kernel; + private Timer timer; + + protected MultiPassKernelSwingWorker(Kernel kernel) { + this.kernel = kernel; + } + + /** Utility method which just invokes {@link Kernel#cancelMultiPass()} on the executing kernel. */ + public void cancelExecution() { + kernel.cancelMultiPass(); + } + + /** This method must invoke one of the {@code kernel}'s execute() methods. */ + protected abstract void executeKernel(Kernel kernel); + + /** This method, which is always invoked on the swing event dispatch thread, should be used to update any components (such as a {@link javax.swing.JProgressBar}) so + * as to reflect the progress of the multi-pass Kernel being executed. + * + * @param passId The passId for the Kernel's current pass, or one of the constant fields returnable by {@link KernelRunner#getCurrentPass()}. + */ + protected abstract void updatePassId(int passId); + + /** Executes the {@link #kernel} via {@link #executeKernel(Kernel)}, whilst also managing progress updates for the kernel's passId. */ + @Override + protected final Void doInBackground() throws Exception { + try { + setUpExecution(); + executeKernel(kernel); + return null; + } + finally { + cleanUpExecution(); + } + } + + private void setUpExecution() { + ActionListener listener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + updatePassId(); + } + }; + timer = new Timer(getPollIntervalMillis(), listener); + timer.setCoalesce(false); + timer.start(); + } + + private void cleanUpExecution() { + timer.stop(); + timer = null; + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + updatePassId(KernelRunner.PASS_ID_COMPLETED_EXECUTION); + } + }); + } + + private void updatePassId() { + int progress = kernel.getCurrentPass(); + updatePassId(progress); + } + + /** The interval at which the Kernel's current passId is polled. Unless overridden, returns {@link #DEFAULT_POLL_INTERVAL}. */ + protected int getPollIntervalMillis() { + return DEFAULT_POLL_INTERVAL; + } +} diff --git a/src/test/java/ConvolutionLargeTest.java b/src/test/java/ConvolutionLargeTest.java index 8056314c4ea8740ccce3e9149215c7ce0d966d93..e69e9f39a22484d224b82366c0c792001c7bdc3e 100644 --- a/src/test/java/ConvolutionLargeTest.java +++ b/src/test/java/ConvolutionLargeTest.java @@ -1,291 +1,291 @@ -/** - * Copyright (c) 2016 - 2017 Syncleus, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* -Copyright (c) 2010-2011, Advanced Micro Devices, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -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. - -Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. - -If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export -laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through -774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, -you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of -Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration -Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, -E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups -D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject -to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 -of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations -under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. - - */ - -import java.io.IOException; -import java.text.MessageFormat; -import java.util.concurrent.TimeUnit; - -import com.aparapi.Kernel; -import com.aparapi.internal.model.CacheEnabler; -import com.aparapi.internal.model.Supplier; - -public class ConvolutionLargeTest{ - - private byte[] inBytes; - - private byte[] outBytes; - - private int width; - - private int height; - - private float _convMatrix3x3[]; - - public ConvolutionLargeTest(String[] _args) throws IOException { - // final File _file = new File(_args.length == 1 ? _args[0] : "testcard.jpg"); - - _convMatrix3x3 = new float[] { - 0f, - -10f, - 0f, - -10f, - 40f, - -10f, - 0f, - -10f, - 0f, - }; - - // BufferedImage inputImage = ImageIO.read(_file); - - // System.out.println(inputImage); - - // height = inputImage.getHeight(); - // - // width = inputImage.getWidth(); - // - // BufferedImage outputImage = new BufferedImage(width, height, inputImage.getType()); - // - // inBytes = ((DataBufferByte) inputImage.getRaster().getDataBuffer()).getData(); - // outBytes = ((DataBufferByte) outputImage.getRaster().getDataBuffer()).getData(); - } - - private void prepareForSize(int pixels) { - int side = (int) Math.sqrt(pixels); - width = side; - height = side; - - inBytes = new byte[width * height * 3]; - outBytes = new byte[width * height * 3]; - } - - public static void main(final String[] _args) throws IOException { - new ConvolutionLargeTest(_args).go(); - } - - private void go() { - boolean testWithoutCaches = true; - int maxRounds = 5; - for (int i = 1; i <= maxRounds; i++) { - System.out.println("-----------------------------"); - int pixels = (1_000 * 1_000 * (1 << (i - 1))) & ~(1 << 10 - 1); - System.out.println(MessageFormat.format("Round #{0}/{1} ({2} pixels)", i, maxRounds, pixels)); - prepareForSize(pixels); - System.out.println("-----------------------------"); - System.out.println(); - testWithSupplier(new ImageConvolutionCreationContext(){ - private ImageConvolution convolution = new ImageConvolution(); - - @Override public Supplier<ImageConvolution> getSupplier() { - return new Supplier<ImageConvolution>(){ - @Override public ImageConvolution get() { - return convolution; - } - }; - } - - @Override public Consumer<ImageConvolution> getDisposer() { - return new Consumer<ImageConvolution>(){ - @Override public void accept(ImageConvolution k) { - // Do nothing - } - }; - } - - @Override public void shutdown() { - convolution.dispose(); - } - - @Override public String getName() { - return "single kernel"; - } - }, 10, testWithoutCaches); - testWithSupplier(new ImageConvolutionCreationContext(){ - @Override public Supplier<ImageConvolution> getSupplier() { - return new Supplier<ImageConvolution>(){ - @Override public ImageConvolution get() { - return new ImageConvolution(); - } - }; - } - - @Override public Consumer<ImageConvolution> getDisposer() { - return new Consumer<ImageConvolution>(){ - @Override public void accept(ImageConvolution k) { - k.dispose(); - } - }; - } - - @Override public void shutdown() { - // Do nothing - } - - @Override public String getName() { - return "multiple kernels"; - } - }, 10, testWithoutCaches); - } - } - - private void testWithSupplier(ImageConvolutionCreationContext imageConvolutionCreationContext, int seconds, - boolean testWithoutCaches) { - System.out.println("Test context: " + imageConvolutionCreationContext.getName()); - CacheEnabler.setCachesEnabled(!testWithoutCaches); - // Warmup - doTest("Warmup (caches " + (testWithoutCaches ? "not " : "") + "enabled)", 2, imageConvolutionCreationContext); - if (testWithoutCaches) { - long timeWithoutCaches = doTest("Without caches", seconds, imageConvolutionCreationContext); - CacheEnabler.setCachesEnabled(true); - long timeWithCaches = doTest("With caches", seconds, imageConvolutionCreationContext); - System.out.println(MessageFormat.format("\tSpeedup: {0} %", 100d * (timeWithoutCaches - timeWithCaches) - / timeWithoutCaches)); - } else { - doTest("With caches", seconds, imageConvolutionCreationContext); - } - } - - // @FunctionalInterface - private interface Consumer<K> { - void accept(K k); - } - - private interface ImageConvolutionCreationContext{ - Supplier<ImageConvolution> getSupplier(); - - Consumer<ImageConvolution> getDisposer(); - - void shutdown(); - - String getName(); - - } - - private long doTest(String name, int seconds, ImageConvolutionCreationContext imageConvolutionCreationContext) { - long totalTime = 0; - Supplier<ImageConvolution> imageConvolutionSupplier = imageConvolutionCreationContext.getSupplier(); - Consumer<ImageConvolution> disposer = imageConvolutionCreationContext.getDisposer(); - System.out.print("\tTesting " + name + "[" + imageConvolutionCreationContext.getName() + "] (" + seconds + " seconds) "); - int calls = 0; - long initialTime = System.nanoTime(); - long maxElapsedNs = TimeUnit.SECONDS.toNanos(seconds); - for (;;) { - long start = System.nanoTime(); - if (start - initialTime > maxElapsedNs) - break; - ImageConvolution imageConvolution = imageConvolutionSupplier.get(); - try { - imageConvolution.applyConvolution(_convMatrix3x3, inBytes, outBytes, width, height); - } finally { - disposer.accept(imageConvolution); - } - - long end = System.nanoTime(); - long roundTime = end - start; - totalTime += roundTime; - // System.out.print("#" + i + " - " + roundTime + "ms "); - // System.out.print(roundTime + " "); - System.out.print("."); - calls++; - } - imageConvolutionCreationContext.shutdown(); - System.out.println(); - System.out.println(MessageFormat.format("\tFinished in {0} s ({1} ms/call, {2} calls)", totalTime / 1e9d, - (totalTime / (calls * 1e6d)), calls)); - System.out.println(); - return totalTime / calls; - } - - final static class ImageConvolution extends Kernel{ - - private float convMatrix3x3[]; - - private int width, height; - - private byte imageIn[], imageOut[]; - - public void processPixel(int x, int y, int w, int h) { - float accum = 0f; - int count = 0; - for (int dx = -3; dx < 6; dx += 3) { - for (int dy = -1; dy < 2; dy += 1) { - final int rgb = 0xff & imageIn[((y + dy) * w) + (x + dx)]; - - accum += rgb * convMatrix3x3[count++]; - } - } - final byte value = (byte) (max(0, min((int) accum, 255))); - imageOut[(y * w) + x] = value; - - } - - @Override public void run() { - final int x = getGlobalId(0) % (width * 3); - final int y = getGlobalId(0) / (width * 3); - - if ((x > 3) && (x < ((width * 3) - 3)) && (y > 1) && (y < (height - 1))) { - processPixel(x, y, width * 3, height); - } - - } - - public void applyConvolution(float[] _convMatrix3x3, byte[] _imageIn, byte[] _imageOut, int _width, int _height) { - imageIn = _imageIn; - imageOut = _imageOut; - width = _width; - height = _height; - convMatrix3x3 = _convMatrix3x3; - execute(3 * width * height); - } - } -} +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +Copyright (c) 2010-2011, Advanced Micro Devices, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +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. + +Neither the name of the copyright holder nor the names of its contributors may 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 HOLDER 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. + +If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export +laws, including but not limited to the U.S. Export Administration Regulations ("EAR"), (15 C.F.R. Sections 730 through +774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, +you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of +Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration +Regulations ("EAR"), you will not (1) export, re-export or release to a national of a country in Country Groups D:1, +E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups +D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject +to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 +of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations +under those regulations, please refer to the U.S. Bureau of Industry and Security's website at http://www.bis.doc.gov/. + + */ + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.concurrent.TimeUnit; + +import com.aparapi.Kernel; +import com.aparapi.internal.model.CacheEnabler; +import com.aparapi.internal.model.Supplier; + +public class ConvolutionLargeTest{ + + private byte[] inBytes; + + private byte[] outBytes; + + private int width; + + private int height; + + private float _convMatrix3x3[]; + + public ConvolutionLargeTest(String[] _args) throws IOException { + // final File _file = new File(_args.length == 1 ? _args[0] : "testcard.jpg"); + + _convMatrix3x3 = new float[] { + 0f, + -10f, + 0f, + -10f, + 40f, + -10f, + 0f, + -10f, + 0f, + }; + + // BufferedImage inputImage = ImageIO.read(_file); + + // System.out.println(inputImage); + + // height = inputImage.getHeight(); + // + // width = inputImage.getWidth(); + // + // BufferedImage outputImage = new BufferedImage(width, height, inputImage.getType()); + // + // inBytes = ((DataBufferByte) inputImage.getRaster().getDataBuffer()).getData(); + // outBytes = ((DataBufferByte) outputImage.getRaster().getDataBuffer()).getData(); + } + + private void prepareForSize(int pixels) { + int side = (int) Math.sqrt(pixels); + width = side; + height = side; + + inBytes = new byte[width * height * 3]; + outBytes = new byte[width * height * 3]; + } + + public static void main(final String[] _args) throws IOException { + new ConvolutionLargeTest(_args).go(); + } + + private void go() { + boolean testWithoutCaches = true; + int maxRounds = 5; + for (int i = 1; i <= maxRounds; i++) { + System.out.println("-----------------------------"); + int pixels = (1_000 * 1_000 * (1 << (i - 1))) & ~(1 << 10 - 1); + System.out.println(MessageFormat.format("Round #{0}/{1} ({2} pixels)", i, maxRounds, pixels)); + prepareForSize(pixels); + System.out.println("-----------------------------"); + System.out.println(); + testWithSupplier(new ImageConvolutionCreationContext(){ + private ImageConvolution convolution = new ImageConvolution(); + + @Override public Supplier<ImageConvolution> getSupplier() { + return new Supplier<ImageConvolution>(){ + @Override public ImageConvolution get() { + return convolution; + } + }; + } + + @Override public Consumer<ImageConvolution> getDisposer() { + return new Consumer<ImageConvolution>(){ + @Override public void accept(ImageConvolution k) { + // Do nothing + } + }; + } + + @Override public void shutdown() { + convolution.dispose(); + } + + @Override public String getName() { + return "single kernel"; + } + }, 10, testWithoutCaches); + testWithSupplier(new ImageConvolutionCreationContext(){ + @Override public Supplier<ImageConvolution> getSupplier() { + return new Supplier<ImageConvolution>(){ + @Override public ImageConvolution get() { + return new ImageConvolution(); + } + }; + } + + @Override public Consumer<ImageConvolution> getDisposer() { + return new Consumer<ImageConvolution>(){ + @Override public void accept(ImageConvolution k) { + k.dispose(); + } + }; + } + + @Override public void shutdown() { + // Do nothing + } + + @Override public String getName() { + return "multiple kernels"; + } + }, 10, testWithoutCaches); + } + } + + private void testWithSupplier(ImageConvolutionCreationContext imageConvolutionCreationContext, int seconds, + boolean testWithoutCaches) { + System.out.println("Test context: " + imageConvolutionCreationContext.getName()); + CacheEnabler.setCachesEnabled(!testWithoutCaches); + // Warmup + doTest("Warmup (caches " + (testWithoutCaches ? "not " : "") + "enabled)", 2, imageConvolutionCreationContext); + if (testWithoutCaches) { + long timeWithoutCaches = doTest("Without caches", seconds, imageConvolutionCreationContext); + CacheEnabler.setCachesEnabled(true); + long timeWithCaches = doTest("With caches", seconds, imageConvolutionCreationContext); + System.out.println(MessageFormat.format("\tSpeedup: {0} %", 100d * (timeWithoutCaches - timeWithCaches) + / timeWithoutCaches)); + } else { + doTest("With caches", seconds, imageConvolutionCreationContext); + } + } + + // @FunctionalInterface + private interface Consumer<K> { + void accept(K k); + } + + private interface ImageConvolutionCreationContext{ + Supplier<ImageConvolution> getSupplier(); + + Consumer<ImageConvolution> getDisposer(); + + void shutdown(); + + String getName(); + + } + + private long doTest(String name, int seconds, ImageConvolutionCreationContext imageConvolutionCreationContext) { + long totalTime = 0; + Supplier<ImageConvolution> imageConvolutionSupplier = imageConvolutionCreationContext.getSupplier(); + Consumer<ImageConvolution> disposer = imageConvolutionCreationContext.getDisposer(); + System.out.print("\tTesting " + name + "[" + imageConvolutionCreationContext.getName() + "] (" + seconds + " seconds) "); + int calls = 0; + long initialTime = System.nanoTime(); + long maxElapsedNs = TimeUnit.SECONDS.toNanos(seconds); + for (;;) { + long start = System.nanoTime(); + if (start - initialTime > maxElapsedNs) + break; + ImageConvolution imageConvolution = imageConvolutionSupplier.get(); + try { + imageConvolution.applyConvolution(_convMatrix3x3, inBytes, outBytes, width, height); + } finally { + disposer.accept(imageConvolution); + } + + long end = System.nanoTime(); + long roundTime = end - start; + totalTime += roundTime; + // System.out.print("#" + i + " - " + roundTime + "ms "); + // System.out.print(roundTime + " "); + System.out.print("."); + calls++; + } + imageConvolutionCreationContext.shutdown(); + System.out.println(); + System.out.println(MessageFormat.format("\tFinished in {0} s ({1} ms/call, {2} calls)", totalTime / 1e9d, + (totalTime / (calls * 1e6d)), calls)); + System.out.println(); + return totalTime / calls; + } + + final static class ImageConvolution extends Kernel{ + + private float convMatrix3x3[]; + + private int width, height; + + private byte imageIn[], imageOut[]; + + public void processPixel(int x, int y, int w, int h) { + float accum = 0f; + int count = 0; + for (int dx = -3; dx < 6; dx += 3) { + for (int dy = -1; dy < 2; dy += 1) { + final int rgb = 0xff & imageIn[((y + dy) * w) + (x + dx)]; + + accum += rgb * convMatrix3x3[count++]; + } + } + final byte value = (byte) (max(0, min((int) accum, 255))); + imageOut[(y * w) + x] = value; + + } + + @Override public void run() { + final int x = getGlobalId(0) % (width * 3); + final int y = getGlobalId(0) / (width * 3); + + if ((x > 3) && (x < ((width * 3) - 3)) && (y > 1) && (y < (height - 1))) { + processPixel(x, y, width * 3, height); + } + + } + + public void applyConvolution(float[] _convMatrix3x3, byte[] _imageIn, byte[] _imageOut, int _width, int _height) { + imageIn = _imageIn; + imageOut = _imageOut; + width = _width; + height = _height; + convMatrix3x3 = _convMatrix3x3; + execute(3 * width * height); + } + } +}