protected void setBinaries(Map<CLDevice, byte[]> binaries) {
    if (this.devices == null) {
      this.devices = new CLDevice[binaries.size()];
      int iDevice = 0;
      for (CLDevice device : binaries.keySet()) this.devices[iDevice++] = device;
    }
    int nDevices = this.devices.length;
    NativeSize[] lengths = new NativeSize[nDevices];
    cl_device_id[] deviceIds = new cl_device_id[nDevices];
    Memory binariesArray = new Memory(Pointer.SIZE * nDevices);
    Memory[] binariesMems = new Memory[nDevices];

    for (int iDevice = 0; iDevice < nDevices; iDevice++) {
      CLDevice device = devices[iDevice];
      byte[] binary = binaries.get(device);

      Memory binaryMem = binariesMems[iDevice] = new Memory(binary.length);
      binaryMem.write(0, binary, 0, binary.length);
      binariesArray.setPointer(iDevice * Pointer.SIZE, binaryMem);

      lengths[iDevice] = toNS(binary.length);
      deviceIds[iDevice] = device.getEntity();
    }
    PointerByReference binariesPtr = new PointerByReference();
    binariesPtr.setPointer(binariesArray);

    IntBuffer errBuff = NIOUtils.directInts(1, ByteOrder.nativeOrder());
    int previousAttempts = 0;
    IntBuffer statuses = NIOUtils.directInts(nDevices, ByteOrder.nativeOrder());
    do {
      entity =
          CL.clCreateProgramWithBinary(
              context.getEntity(), nDevices, deviceIds, lengths, binariesPtr, statuses, errBuff);
    } while (failedForLackOfMemory(errBuff.get(0), previousAttempts++));
  }
  /** Find a kernel by its functionName, and optionally bind some arguments to it. */
  public CLKernel createKernel(String name, Object... args) throws CLBuildException {
    synchronized (this) {
      if (!built) build();
    }
    IntBuffer errBuff = NIOUtils.directInts(1, ByteOrder.nativeOrder());
    cl_kernel kernel;
    int previousAttempts = 0;
    do {
      kernel = CL.clCreateKernel(getEntity(), name, errBuff);
    } while (failedForLackOfMemory(errBuff.get(0), previousAttempts++));

    CLKernel kn = new CLKernel(this, name, kernel);
    kn.setArgs(args);
    return kn;
  }
  public synchronized void allocate() {
    if (entity != null) throw new IllegalThreadStateException("Program was already allocated !");

    if (passMacrosAsSources) {
      if (macros != null && !macros.isEmpty()) {
        StringBuilder b = new StringBuilder();
        for (Map.Entry<String, Object> m : macros.entrySet())
          b.append("#define " + m.getKey() + " " + m.getValue() + "\n");
        this.sources.add(0, b.toString());
      }
    }

    if (!"false".equals(System.getProperty("javacl.adjustDoubleExtension"))
        && !"0".equals(System.getenv("JAVACL_ADJUST_DOUBLE_EXTENSION"))) {
      for (int i = 0, len = sources.size(); i < len; i++) {
        String source = sources.get(i);
        for (CLDevice device : getDevices())
          source = device.replaceDoubleExtensionByExtensionActuallyAvailable(source);
        sources.set(i, source);
        // TODO keep different sources for each device !!!
      }
    }

    String[] sources = this.sources.toArray(new String[this.sources.size()]);
    NativeSize[] lengths = new NativeSize[sources.length];
    for (int i = 0; i < sources.length; i++) {
      lengths[i] = toNS(sources[i].length());
    }
    IntBuffer errBuff = NIOUtils.directInts(1, ByteOrder.nativeOrder());
    cl_program program;
    int previousAttempts = 0;
    do {
      program =
          CL.clCreateProgramWithSource(
              context.getEntity(), sources.length, sources, lengths, errBuff);
    } while (failedForLackOfMemory(errBuff.get(0), previousAttempts++));
    entity = program;
  }