//#OPTIONS: CPP

/*
  Stable pointers are all allocated in the h$StablePtrData buffer and
  can therefore be distinguished by offset

  StablePtr# is treated as Word32# when it comes to writing and reading them
 */

 #ifdef GHCJS_TRACE_STABLEPTR
 function h$logStablePtr(args) { h$log.apply(h$log,arguments); }
 #define TRACE_STABLEPTR(args...) h$logStablePtr(args)
 #else
 #define TRACE_STABLEPTR(args...)
 #endif

var h$stablePtrData = [null];
var h$stablePtrBuf  = h$newByteArray(8);
var h$stablePtrN    = 1;
var h$stablePtrFree = [];

function h$makeStablePtr(v) {
  TRACE_STABLEPTR("makeStablePtr")
  if(!v) return 0;
  var slot = h$stablePtrFree.pop();
  if(slot === undefined) {
    slot = h$stablePtrN++;
  }
  TRACE_STABLEPTR("  -> slot:" + slot)
  h$stablePtrData[slot] = v;
  return slot << 2;
}

var h$foreignExports = [];
function h$foreignExport(f, packageName, moduleName, functionName, typeSig) {
  h$foreignExports.push({ exported: f,
                          package: packageName,
                          mod:  moduleName,
                          name: functionName,
                          sig: typeSig
                        });
  // console.log("foreign export:", f, packageName, moduleName, functionName, typeSig);
  h$makeStablePtr(f);
  if(typeof exports === 'object') {
    if(typeof exports[functionName] === 'undefined') {
      exports[functionName] = f;
    }
  }
}
/*
function h$foreignExportStablePtr(x) {
  // h$makeStablePtr(x);
}
*/
function h$deRefStablePtr(stable_o) {
  var slot = stable_o >> 2;
  return h$stablePtrData[slot];
}

function h$hs_free_stable_ptr(stable_d, stable_o) {
  var slot = stable_o >> 2;
  TRACE_STABLEPTR("hs_free_stable_ptr")
  if(h$stablePtrData[slot] !== null) {
    h$stablePtrData[slot] = null;
    h$stablePtrFree.push(slot);
  }
}

// not strictly stableptr, but we make it work only for stable pointers
function h$addrToAny(addr_v, addr_o) {
  TRACE_STABLEPTR("addrToAny")
  TRACE_STABLEPTR(addr_v === h$stablePtrBuf)
  var slot = addr_o >> 2;
  return h$stablePtrData[slot];
}
