Example #1
0
Error Context::livenessAnalysis() {
  uint32_t bLen = static_cast<uint32_t>(
    ((_contextVd.getLength() + BitArray::kEntityBits - 1) / BitArray::kEntityBits));

  // No variables.
  if (bLen == 0)
    return kErrorOk;

  HLFunc* func = getFunc();
  HLJump* from = NULL;

  LivenessTarget* ltCur = NULL;
  LivenessTarget* ltUnused = NULL;

  PodList<HLNode*>::Link* retPtr = _returningList.getFirst();
  ASMJIT_ASSERT(retPtr != NULL);

  HLNode* node = retPtr->getValue();

  size_t varMapToVaListOffset = _varMapToVaListOffset;
  BitArray* bCur = newBits(bLen);

  if (bCur == NULL)
    goto _NoMemory;

  // Allocate bits for code visited first time.
_OnVisit:
  for (;;) {
    if (node->hasLiveness()) {
      if (bCur->_addBitsDelSource(node->getLiveness(), bCur, bLen))
        goto _OnPatch;
      else
        goto _OnDone;
    }

    BitArray* bTmp = copyBits(bCur, bLen);
    if (bTmp == NULL)
      goto _NoMemory;

    node->setLiveness(bTmp);
    VarMap* map = node->getMap();

    if (map != NULL) {
      uint32_t vaCount = map->getVaCount();
      VarAttr* vaList = reinterpret_cast<VarAttr*>(((uint8_t*)map) + varMapToVaListOffset);

      for (uint32_t i = 0; i < vaCount; i++) {
        VarAttr* va = &vaList[i];
        VarData* vd = va->getVd();

        uint32_t flags = va->getFlags();
        uint32_t ctxId = vd->getLocalId();

        if ((flags & kVarAttrWAll) && !(flags & kVarAttrRAll)) {
          // Write-Only.
          bTmp->setBit(ctxId);
          bCur->delBit(ctxId);
        }
        else {
          // Read-Only or Read/Write.
          bTmp->setBit(ctxId);
          bCur->setBit(ctxId);
        }
      }
    }

    if (node->getType() == kHLNodeTypeLabel)
      goto _OnTarget;

    if (node == func)
      goto _OnDone;

    ASMJIT_ASSERT(node->getPrev());
    node = node->getPrev();
  }

  // Patch already generated liveness bits.
_OnPatch:
  for (;;) {
    ASMJIT_ASSERT(node->hasLiveness());
    BitArray* bNode = node->getLiveness();

    if (!bNode->_addBitsDelSource(bCur, bLen))
      goto _OnDone;

    if (node->getType() == kHLNodeTypeLabel)
      goto _OnTarget;

    if (node == func)
      goto _OnDone;

    node = node->getPrev();
  }

_OnTarget:
  if (static_cast<HLLabel*>(node)->getNumRefs() != 0) {
    // Push a new LivenessTarget onto the stack if needed.
    if (ltCur == NULL || ltCur->node != node) {
      // Allocate a new LivenessTarget object (from pool or zone).
      LivenessTarget* ltTmp = ltUnused;

      if (ltTmp != NULL) {
        ltUnused = ltUnused->prev;
      }
      else {
        ltTmp = _zoneAllocator.allocT<LivenessTarget>(
          sizeof(LivenessTarget) - sizeof(BitArray) + bLen * sizeof(uintptr_t));

        if (ltTmp == NULL)
          goto _NoMemory;
      }

      // Initialize and make current - ltTmp->from will be set later on.
      ltTmp->prev = ltCur;
      ltTmp->node = static_cast<HLLabel*>(node);
      ltCur = ltTmp;

      from = static_cast<HLLabel*>(node)->getFrom();
      ASMJIT_ASSERT(from != NULL);
    }
    else {
      from = ltCur->from;
      goto _OnJumpNext;
    }

    // Visit/Patch.
    do {
      ltCur->from = from;
      bCur->copyBits(node->getLiveness(), bLen);

      if (!from->hasLiveness()) {
        node = from;
        goto _OnVisit;
      }

      // Issue #25: Moved '_OnJumpNext' here since it's important to patch
      // code again if there are more live variables than before.
_OnJumpNext:
      if (bCur->delBits(from->getLiveness(), bLen)) {
        node = from;
        goto _OnPatch;
      }

      from = from->getJumpNext();
    } while (from != NULL);

    // Pop the current LivenessTarget from the stack.
    {
      LivenessTarget* ltTmp = ltCur;

      ltCur = ltCur->prev;
      ltTmp->prev = ltUnused;
      ltUnused = ltTmp;
    }
  }

  bCur->copyBits(node->getLiveness(), bLen);
  node = node->getPrev();

  if (node->isJmp() || !node->isFetched())
    goto _OnDone;

  if (!node->hasLiveness())
    goto _OnVisit;

  if (bCur->delBits(node->getLiveness(), bLen))
    goto _OnPatch;

_OnDone:
  if (ltCur != NULL) {
    node = ltCur->node;
    from = ltCur->from;

    goto _OnJumpNext;
  }

  retPtr = retPtr->getNext();
  if (retPtr != NULL) {
    node = retPtr->getValue();
    goto _OnVisit;
  }

  return kErrorOk;

_NoMemory:
  return setLastError(kErrorNoHeapMemory);
}