/*
  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;
}

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];
}
