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>
-    *  &#64Local 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>
-    *  &#64Constant 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>
-    *  &#64PrivateMemorySpace(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>
-    *  &#64Local 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>
-    *  &#64Constant 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>
-    *  &#64PrivateMemorySpace(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>
+    *  &#64Local 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>
+    *  &#64Constant 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>
+    *  &#64PrivateMemorySpace(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>
+    *  &#64Local 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>
+    *  &#64Constant 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>
+    *  &#64PrivateMemorySpace(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&lt3)</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&lt3 || i&gt10)</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&lt3)</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&lt3 || i&gt10)</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&ltn&gt                               |
-             *                 |              / iload&ltn&gt            Increment(varref&ltn&gt++)
-             *          0, 0  istore&ltn&gt - iadd                       |
-             *                 |              \ i_const_1            |
-             *                 B                                     B
-             *                 
-             *                 A                                     A
-             *                 |                                     |
-             *         +1, 0  &ltt&gtload&ltn&gt                             |
-             *                 |                      / iload&ltn&gt    Increment( varref&ltn&gt++)
-             *          0, 0  &ltt&gtstore&ltn&gt - i2&ltt&gt 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&ltn&gt                               |
+             *                 |              / iload&ltn&gt            Increment(varref&ltn&gt++)
+             *          0, 0  istore&ltn&gt - iadd                       |
+             *                 |              \ i_const_1            |
+             *                 B                                     B
+             *                 
+             *                 A                                     A
+             *                 |                                     |
+             *         +1, 0  &ltt&gtload&ltn&gt                             |
+             *                 |                      / iload&ltn&gt    Increment( varref&ltn&gt++)
+             *          0, 0  &ltt&gtstore&ltn&gt - i2&ltt&gt 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);
+      }
+   }
+}