diff --git a/CHANGELOG.md b/CHANGELOG.md
index 03d2fcf5ff18f9f1d9ccba61fe6547f92847f78a..c18842345c0fcba6b8d4e830188900847d1ebba2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
## 1.3.1
+* Fixed JVM crash with multi-dimensional arrays in Local memory (2D and 3D local arrays are now supported)
+
## 1.3.0
* createProgram in Java had the wrong signature producing a unsatisfied link exception that is now fixed.
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 0d114df46fe8f7235291653662df55ec3de0bfda..30c0be3ef09fa7d4df7296f8ec32b765eaead2d0 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -9,6 +9,7 @@
* Steven Libby
* Paul Miner
* Lorenzo Gallucci
+* Luis Mendes <luis.p.mendes@gmail.com>
# Details
@@ -26,3 +27,4 @@ Below are some of the specific details of various contributions.
* Steven Libby and Ryan Lamothe for #10 (Support for OpenMP, major refactoring cleanup and support for multidim arrays) March 28th 2013
* Paul Miner issue #61 and #115 (JTP Speed up and fixes to explicit puts) June 13th 2013
& lgalluci for his fix for issue #121 (incorrect toString for 3D ranges) July 6th 2013
+* Luis Mendes Issue #51 JVM crash when using multi-dimensional local arrays (refs #51)
\ No newline at end of file
diff --git a/src/cpp/runKernel/Aparapi.cpp b/src/cpp/runKernel/Aparapi.cpp
index 956a67ba442d4984a66d2638d34127eb41ffa511..85ae3a2edad5af5d39c56a2c2af1afacba3fcc68 100644
--- a/src/cpp/runKernel/Aparapi.cpp
+++ b/src/cpp/runKernel/Aparapi.cpp
@@ -48,7 +48,10 @@
#include "AparapiBuffer.h"
#include "CLHelper.h"
#include "List.h"
+#include "Util.h"
#include <algorithm>
+#include <string>
+#include <sstream>
static const int PASS_ID_PREPARING_EXECUTION = -2;
static const int PASS_ID_COMPLETED_EXECUTION = -1;
@@ -668,21 +671,54 @@ void processLocalBuffer(JNIEnv* jenv, JNIContext* jniContext, KernelArg* arg, in
cl_int status = CL_SUCCESS;
// what if local buffer size has changed? We need a check for resize here.
if (jniContext->firstRun) {
- status = arg->setLocalBufferArg(jenv, argIdx, argPos, config->isVerbose());
- if(status != CL_SUCCESS) throw CLException(status,"clSetKernelArg() (local)");
+ //To retrieve all fields of aparapiBuffer from Java for this local arg.
+ arg->aparapiBuffer->flatten(jenv,arg);
+
+ status = arg->setLocalAparapiBufferArg(jenv, argIdx, argPos, config->isVerbose());
+ if(status != CL_SUCCESS) {
+ arg->aparapiBuffer->deleteBuffer(arg);
+ throw CLException(status,"clSetKernelArg() (local)");
+ }
// Add the array length if needed
if (arg->usesArrayLength()) {
- arg->syncJavaArrayLength(jenv);
-
for(int i = 0; i < arg->aparapiBuffer->numDims; i++)
{
- int length = arg->aparapiBuffer->lens[i];
- status = clSetKernelArg(jniContext->kernel, argPos, sizeof(jint), &length);
- if (config->isVerbose()){
- fprintf(stderr, "runKernel arg %d %s, javaArrayLength = %d\n", argIdx, arg->name, length);
- }
- if(status != CL_SUCCESS) throw CLException(status,"clSetKernelArg (array length)");
+ if (arg->aparapiBuffer->lens == NULL) {
+ std::string str = "runKernel arg " + patch::to_string(argIdx) + " " + arg->name +
+ " - AparapiBuffer lens field is NULL at dim " + patch::to_string(i+1) + " of " +
+ patch::to_string(arg->aparapiBuffer->numDims) + "\n";
+ arg->aparapiBuffer->deleteBuffer(arg);
+ throw CLException(CL_INVALID_VALUE, str.c_str());
+ }
+ int length = arg->aparapiBuffer->lens[i];
+ argPos++;
+ status = clSetKernelArg(jniContext->kernel, argPos, sizeof(cl_uint), &length);
+ if(status != CL_SUCCESS) {
+ arg->aparapiBuffer->deleteBuffer(arg);
+ throw CLException(status,"clSetKernelArg (buffer length)");
+ }
+ if (config->isVerbose()){
+ fprintf(stderr, "runKernel arg %d %s, length = %d\n", argIdx, arg->name, length);
+ }
+
+ if (arg->aparapiBuffer->offsets == NULL) {
+ std::string str = "runKernel arg " + patch::to_string(argIdx) + " " + arg->name +
+ " - AparapiBuffer offsets field is NULL at dim " + patch::to_string(i+1) + " of " +
+ patch::to_string(arg->aparapiBuffer->numDims) + "\n";
+ arg->aparapiBuffer->deleteBuffer(arg);
+ throw CLException(CL_INVALID_VALUE, str.c_str());
+ }
+ int offset = arg->aparapiBuffer->offsets[i];
+ argPos++;
+ status = clSetKernelArg(jniContext->kernel, argPos, sizeof(cl_uint), &offset);
+ if(status != CL_SUCCESS) {
+ arg->aparapiBuffer->deleteBuffer(arg);
+ throw CLException(status,"clSetKernelArg (buffer offset)");
+ }
+ if (config->isVerbose()){
+ fprintf(stderr, "runKernel arg %d %s, offsets = %d\n", argIdx, arg->name, offset);
+ }
}
}
} else {
@@ -934,6 +970,14 @@ int getReadEvents(JNIEnv* jenv, JNIContext* jniContext) {
for (int i=0; i< jniContext->argc; i++) {
KernelArg *arg = jniContext->args[i];
+ if (arg->isLocal() && arg->isAparapiBuffer()) {
+ if (config->isVerbose()) {
+ fprintf(stderr, "Freeing local aparapi buffer for arg %d", arg->name);
+ }
+ arg->aparapiBuffer->deleteBuffer(arg);
+ continue;
+ }
+
if (arg->needToEnqueueRead()){
if (arg->isConstant()){
fprintf(stderr, "reading %s\n", arg->name);
diff --git a/src/cpp/runKernel/Util.h b/src/cpp/runKernel/Util.h
new file mode 100644
index 0000000000000000000000000000000000000000..1b1916f279e0d7dee2348c39687afdd49bce9fc2
--- /dev/null
+++ b/src/cpp/runKernel/Util.h
@@ -0,0 +1,25 @@
+/*
+ * Util.h
+ *
+ * Created on: 24/04/2018
+ * Author: lpnm
+ */
+
+#ifndef SRC_CPP_RUNKERNEL_UTIL_H_
+#define SRC_CPP_RUNKERNEL_UTIL_H_
+
+#include <string>
+#include <sstream>
+
+namespace patch
+{
+ template < typename T > std::string to_string( const T& n )
+ {
+ std::ostringstream stm ;
+ stm << n ;
+ return stm.str() ;
+ }
+}
+
+
+#endif /* SRC_CPP_RUNKERNEL_UTIL_H_ */