diff --git a/com.amd.aparapi.jni/build.xml b/com.amd.aparapi.jni/build.xml
index f720e85d16066d21630cee991501b676252602bc..5d70e63e88e8f39fa873f7042079e117ec086370 100644
--- a/com.amd.aparapi.jni/build.xml
+++ b/com.amd.aparapi.jni/build.xml
@@ -517,6 +517,7 @@ First consider editing the properties in build.properties
          <arg value="src/cpp/opencljni.cpp" />
          <arg value="src/cpp/jniHelper.cpp" />
          <arg value="src/cpp/clHelper.cpp" />
+         <arg value="src/cpp/agent.cpp" />
          <arg value="-L${amd.app.sdk.dir}/lib/${x86_or_x86_64}" />
          <arg value="-lOpenCL" />
       </exec>
diff --git a/com.amd.aparapi.jni/src/cpp/agent.cpp b/com.amd.aparapi.jni/src/cpp/agent.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e13a78d8acdafb35b6a6f46784d3044362bab9fa
--- /dev/null
+++ b/com.amd.aparapi.jni/src/cpp/agent.cpp
@@ -0,0 +1,166 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <jni.h>
+#include <jvmti.h>
+
+
+
+
+jvmtiEnv     *jvmti;
+JavaVM       *jvm;
+
+static void JNICALL vmInit(jvmtiEnv *_jvmtiEnv, JNIEnv* _jniEnv, jthread thread) {
+   fprintf(stdout, "from agent vmInit()\n");
+   /*
+   if (_jniEnv->ExceptionOccurred()) {
+      fprintf(stdout, "Exception raised\n");
+      _jniEnv->ExceptionDescribe();
+      _jniEnv->ExceptionClear();
+   }
+   jclass classId = _jniEnv->FindClass("C");
+   classId = _jniEnv->FindClass("java/lang/String");
+   if (_jniEnv->ExceptionOccurred()) {
+      fprintf(stdout, "Exception raised\n");
+      _jniEnv->ExceptionDescribe();
+      _jniEnv->ExceptionClear();
+   }
+   */
+}
+
+class NameToBytes{
+  private:
+    const char *name;
+    const jint len;
+    const unsigned char *bytes;
+    const NameToBytes* next;
+  public:
+    NameToBytes(const NameToBytes *_head, const char *_name, const jint _len, const unsigned char *_bytes) : len(_len) {
+      int nameLen = strlen(_name)+1;
+      name = new char [nameLen];
+      memcpy((void*)name, (void*)_name, nameLen);
+      for (char *ptr = (char *)name; *ptr; ptr++){
+         if (*ptr == '/'){
+            *ptr = '.';
+         }
+      }
+
+    //  name = (const char*)strdup(_name);
+      bytes = new unsigned char[len];
+      memcpy((void*)bytes, (void*)_bytes, len);
+      next = _head;
+    }
+    ~NameToBytes(){
+      delete name;
+      delete bytes;
+    }
+    const unsigned char *getBytes(){
+       return(bytes);
+    }
+    const char *getName(){
+       return(name);
+    }
+    const jint getLen(){
+       return(len);
+    }
+    const NameToBytes *getNext(){
+       return(next);
+    }
+};
+
+NameToBytes *head = NULL;
+
+/*
+ * Class:     com_amd_aparapi_OpenCLJNI
+ * Method:    getClassBytes
+ * Signature: (Ljava/lang/String;)V
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+JNIEXPORT jbyteArray JNICALL Java_com_amd_aparapi_OpenCLJNI_getBytes (JNIEnv *jenv, jobject instance, jstring className){
+     jbyteArray bytes = NULL;
+     const char *nameChars = jenv->GetStringUTFChars(className, NULL);
+     fprintf(stdout, "inside getBytes(\"%s\")\n", nameChars);
+     for (NameToBytes *ptr = head; ptr != NULL; ptr=(NameToBytes *)ptr->getNext()){
+        //fprintf(stdout, "testing \"%s\"==\"%s\"\n", nameChars, ptr->getName());
+        if (!strcmp(ptr->getName(), nameChars)){
+           fprintf(stdout, "found bytes for \"%s\"\n", nameChars);
+           bytes = jenv->NewByteArray(ptr->getLen());
+           //fprintf(stdout, "created byte array size= %d\n", ptr->getLen());
+           jenv->SetByteArrayRegion(bytes, (jint)0, (jint)ptr->getLen() , (jbyte*)ptr->getBytes());
+           break;
+        }
+     }
+     if (bytes == NULL){
+        fprintf(stdout, "failed to find bytes for \"%s\"\n", nameChars);
+     }
+     jenv->ReleaseStringUTFChars(className, nameChars);
+     return (bytes);
+}
+#ifdef __cplusplus
+}
+#endif
+
+
+static void JNICALL cbClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv* jni_env,
+            jclass class_being_redefined,
+            jobject loader,
+            const char* name,
+            jobject protection_domain,
+            jint class_data_len,
+            const unsigned char* class_data,
+            jint* new_class_data_len,
+            unsigned char** new_class_data){
+//   fprintf(stdout, "from agent classFileLoadHook(%s)\n", name);
+   head =  new NameToBytes(head, name, class_data_len, class_data);
+}
+
+
+JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
+   jint                returnValue = 0; // OK
+   jint                rc;
+   jvmtiError          err;
+   jvmtiCapabilities   capabilities;
+   jvmtiEventCallbacks callbacks;
+   fprintf(stdout, "Agent_Onload()\n");
+
+   // Get a handle on the JVM.
+   jvm = vm;
+
+   /* Get JVMTI environment */
+   rc = vm->GetEnv((void **)&jvmti, JVMTI_VERSION);
+   if (rc != JNI_OK) {
+      fprintf(stderr, "ERROR: Unable to create jvmtiEnv, GetEnv failed, error=%d\n", rc);
+      returnValue = -1;
+   }else{
+      /* Get/Add JVMTI capabilities */ 
+      if ((err = jvmti->GetCapabilities(&capabilities) ) != JVMTI_ERROR_NONE) {
+         fprintf(stderr, "ERROR: GetCapabilities failed, error=%d\n", err);
+         returnValue = -1;
+      }else{
+         capabilities.can_tag_objects = 1;
+         capabilities.can_generate_all_class_hook_events = 1;
+         if ((err = jvmti->AddCapabilities(&capabilities))!= JVMTI_ERROR_NONE) {
+            fprintf(stderr, "ERROR: AddCapabilities failed, error=%d\n", err);
+            returnValue = -1;
+         }else{
+            /* Set callbacks and enable event notifications */
+            memset(&callbacks, 0, sizeof(callbacks));
+            callbacks.VMInit = &vmInit;
+            callbacks.ClassFileLoadHook = &cbClassFileLoadHook;
+
+            jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
+            jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
+            jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
+         }
+      }
+   }
+   return returnValue;
+}
+
+/* Agent_OnUnload() is called last */
+JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) {
+   fprintf(stdout, "Agent_OnUnload()\n");
+}
+
diff --git a/com.amd.aparapi/src/java/com/amd/aparapi/ClassModel.java b/com.amd.aparapi/src/java/com/amd/aparapi/ClassModel.java
index e75266b6e04198ae31a0d4b1602856a29daf6021..fed2eb1378bec2cb593927a21e17948d2e4abe2e 100644
--- a/com.amd.aparapi/src/java/com/amd/aparapi/ClassModel.java
+++ b/com.amd.aparapi/src/java/com/amd/aparapi/ClassModel.java
@@ -38,6 +38,7 @@ under those regulations, please refer to the U.S. Bureau of Industry and Securit
 package com.amd.aparapi;
 
 import java.io.InputStream;
+import java.io.ByteArrayInputStream;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -152,6 +153,11 @@ class ClassModel{
 
    }
 
+   ClassModel(Class<?> _clazz,  byte[] _bytes) throws ClassParseException {
+      clazz = _clazz;
+      parse(new ByteArrayInputStream(_bytes));
+   }
+
    /**
     * Determine if this is the superclass of some other named class.
     * 
diff --git a/com.amd.aparapi/src/java/com/amd/aparapi/Config.java b/com.amd.aparapi/src/java/com/amd/aparapi/Config.java
index dad7ffb41ae8c7174cbfd412d26c260230bc4195..f45c3f8e6f7e7f814ee0aa3e52d7e3e6f2658ca8 100644
--- a/com.amd.aparapi/src/java/com/amd/aparapi/Config.java
+++ b/com.amd.aparapi/src/java/com/amd/aparapi/Config.java
@@ -56,6 +56,14 @@ class Config{
 
    private static final String propPkgName = Config.class.getPackage().getName();
 
+   /**
+    * Allows the user to request to use a jvmti agent to access JNI code rather than loading explicitly.
+    * 
+    * Usage -agentpath=/full/path/to/agent.dll -Dcom.amd.aparapi.useAgent=true
+    */
+    
+   static final boolean useAgent = Boolean.getBoolean(propPkgName + ".useAgent");
+
    static final boolean disableUnsafe = Boolean.getBoolean(propPkgName + ".disableUnsafe");
 
    /**
diff --git a/com.amd.aparapi/src/java/com/amd/aparapi/KernelRunner.java b/com.amd.aparapi/src/java/com/amd/aparapi/KernelRunner.java
index 8091cf52a399be44bcf0005353196d723903fc02..b0cc46dfc69b639cca90c67ec80bdd9626b1dc37 100644
--- a/com.amd.aparapi/src/java/com/amd/aparapi/KernelRunner.java
+++ b/com.amd.aparapi/src/java/com/amd/aparapi/KernelRunner.java
@@ -1371,7 +1371,12 @@ class KernelRunner{
          if ((device == null) || (device instanceof OpenCLDevice)) {
             if (entryPoint == null) {
                try {
-                  ClassModel classModel = new ClassModel(kernel.getClass());
+                  ClassModel classModel = null;
+                  if (Config.useAgent){
+                     classModel = new ClassModel(kernel.getClass(), OpenCLJNI.getJNI().getBytes(kernel.getClass().getName()));
+                  }else{
+                     classModel = new ClassModel(kernel.getClass());
+                  }
                   entryPoint = classModel.getEntrypoint(_entrypointName, kernel);
                } catch (Exception exception) {
                   return warnFallBackAndExecute(_entrypointName, _range, _passes, exception);
diff --git a/com.amd.aparapi/src/java/com/amd/aparapi/OpenCLJNI.java b/com.amd.aparapi/src/java/com/amd/aparapi/OpenCLJNI.java
index 1ba814c5d0caeac849994ceeeca808144685b558..fbb6acd7b0b38a9cc94211e1b75a27430f52dc05 100644
--- a/com.amd.aparapi/src/java/com/amd/aparapi/OpenCLJNI.java
+++ b/com.amd.aparapi/src/java/com/amd/aparapi/OpenCLJNI.java
@@ -8,29 +8,34 @@ public class OpenCLJNI{
 
    static boolean openCLAvailable = false;
    static {
-      String arch = System.getProperty("os.arch");
-      logger.fine("arch = " + arch);
-      String aparapiLibraryName = null;
-
-      if (arch.equals("amd64") || arch.equals("x86_64")) {
-         aparapiLibraryName = "aparapi_x86_64";
-      } else if (arch.equals("x86") || arch.equals("i386")) {
-         aparapiLibraryName = "aparapi_x86";
-      } else {
-         logger.warning("Expected property os.arch to contain amd64, x86_64, x86 or i386 but instead found " + arch
-               + " as a result we don't know which aparapi to attempt to load.");
-      }
-      if (aparapiLibraryName != null) {
-         logger.fine("attempting to load aparapi shared lib " + aparapiLibraryName);
-         try {
-            Runtime.getRuntime().loadLibrary(aparapiLibraryName);
-            openCLAvailable = true;
-         } catch (UnsatisfiedLinkError e) {
-            System.out
-                  .println("Check your environment. Failed to load aparapi native library "
-                        + aparapiLibraryName
-                        + " or possibly failed to locate opencl native library (opencl.dll/opencl.so). Ensure that both are in your PATH (windows) or in LD_LIBRARY_PATH (linux).");
+      if (Config.useAgent){
+         logger.fine("Using agent!");
+         openCLAvailable = true;
+      }else{
+         String arch = System.getProperty("os.arch");
+         logger.fine("arch = " + arch);
+         String aparapiLibraryName = null;
 
+         if (arch.equals("amd64") || arch.equals("x86_64")) {
+            aparapiLibraryName = "aparapi_x86_64";
+         } else if (arch.equals("x86") || arch.equals("i386")) {
+            aparapiLibraryName = "aparapi_x86";
+         } else {
+            logger.warning("Expected property os.arch to contain amd64, x86_64, x86 or i386 but instead found " + arch
+                  + " as a result we don't know which aparapi to attempt to load.");
+         }
+         if (aparapiLibraryName != null) {
+            logger.fine("attempting to load aparapi shared lib " + aparapiLibraryName);
+            try {
+               Runtime.getRuntime().loadLibrary(aparapiLibraryName);
+               openCLAvailable = true;
+            } catch (UnsatisfiedLinkError e) {
+               System.out
+                     .println("Check your environment. Failed to load aparapi native library "
+                           + aparapiLibraryName
+                           + " or possibly failed to locate opencl native library (opencl.dll/opencl.so). Ensure that both are in your PATH (windows) or in LD_LIBRARY_PATH (linux).");
+   
+            }
          }
       }
    }
@@ -53,6 +58,8 @@ public class OpenCLJNI{
 
    native public void getMem(OpenCLProgram program, OpenCLMem mem);
 
+   native public byte[] getBytes(String className);
+
    public boolean isOpenCLAvailable() {
       return (openCLAvailable);
    }
diff --git a/examples/nbody/nbody-agent.sh b/examples/nbody/nbody-agent.sh
new file mode 100644
index 0000000000000000000000000000000000000000..6ccb51f4f50c58cee17c6e5e9adfb3a49fc48d56
--- /dev/null
+++ b/examples/nbody/nbody-agent.sh
@@ -0,0 +1,11 @@
+java \
+  -agentpath:../../com.amd.aparapi.jni/dist/libaparapi_x86_64.so\
+  -Dcom.amd.aparapi.useAgent=true\
+  -Djava.library.path=../third-party/jogamp \
+  -Dcom.amd.aparapi.executionMode=$1 \
+  -Dbodies=$2 \
+  -Dheight=600 \
+  -Dwidth=600 \
+  -classpath ../third-party/jogamp/jogl-all.jar:../third-party/jogamp/gluegen-rt.jar:../../com.amd.aparapi/dist/aparapi.jar:nbody.jar \
+  com.amd.aparapi.examples.nbody.Main 
+
diff --git a/samples/life/life-agent.sh b/samples/life/life-agent.sh
new file mode 100644
index 0000000000000000000000000000000000000000..55b917eed8f32798dbfe3682a58ec09d69763314
--- /dev/null
+++ b/samples/life/life-agent.sh
@@ -0,0 +1,6 @@
+java\
+ -agentpath:../../com.amd.aparapi.jni/dist/libaparapi_x86_64.so\
+ -Dcom.amd.aparapi.executionMode=$1\
+ -Dcom.amd.aparapi.useAgent=true\
+ -classpath ../../com.amd.aparapi/dist/aparapi.jar:life.jar\
+ com.amd.aparapi.sample.life.Main
diff --git a/samples/mandel/mandel-agent.sh b/samples/mandel/mandel-agent.sh
new file mode 100644
index 0000000000000000000000000000000000000000..3c82e7de596c2ced3a24ed9d2a248aa2c9bc131e
--- /dev/null
+++ b/samples/mandel/mandel-agent.sh
@@ -0,0 +1,7 @@
+java\
+ -agentpath:../../com.amd.aparapi.jni/dist/libaparapi_x86_64.so\
+ -Djava.library.path=../../com.amd.aparapi.jni/dist\
+ -Dcom.amd.aparapi.useAgent=true\
+ -Dcom.amd.aparapi.executionMode=$1\
+ -classpath ../../com.amd.aparapi/dist/aparapi.jar:mandel.jar\
+ com.amd.aparapi.sample.mandel.Main