示例#1
0
Error Context::compile(HLFunc* func) {
  HLNode* end = func->getEnd();
  HLNode* stop = end->getNext();

  _func = func;
  _stop = stop;
  _extraBlock = end;

  ASMJIT_PROPAGATE_ERROR(fetch());
  ASMJIT_PROPAGATE_ERROR(removeUnreachableCode());
  ASMJIT_PROPAGATE_ERROR(livenessAnalysis());

  Compiler* compiler = getCompiler();

#if !defined(ASMJIT_DISABLE_LOGGER)
  if (compiler->getAssembler()->hasLogger())
    ASMJIT_PROPAGATE_ERROR(annotate());
#endif // !ASMJIT_DISABLE_LOGGER

  ASMJIT_PROPAGATE_ERROR(translate());

  if (compiler->hasFeature(kCompilerFeatureEnableScheduler))
    ASMJIT_PROPAGATE_ERROR(schedule());

  // We alter the compiler cursor, because it doesn't make sense to reference
  // it after compilation - some nodes may disappear and it's forbidden to add
  // new code after the compilation is done.
  compiler->_setCursor(NULL);

  return kErrorOk;
}
示例#2
0
Error X86Compiler::finalize() {
  X86Assembler* assembler = getAssembler();
  if (assembler == NULL)
    return kErrorOk;

  // Flush the global constant pool.
  if (_globalConstPoolLabel.isInitialized()) {
    embedConstPool(_globalConstPoolLabel, _globalConstPool);

    _globalConstPoolLabel.reset();
    _globalConstPool.reset();
  }

  if (_firstNode == NULL)
    return kErrorOk;

  X86Context context(this);
  Error error = kErrorOk;

  HLNode* node = _firstNode;
  HLNode* start;

  // Find all functions and use the `X86Context` to translate/emit them.
  do {
    start = node;
    _resetTokenGenerator();

    if (node->getType() == kHLNodeTypeFunc) {
      node = static_cast<X86FuncNode*>(start)->getEnd();
      error = context.compile(static_cast<X86FuncNode*>(start));

      if (error != kErrorOk)
        break;
    }

    do {
      node = node->getNext();
    } while (node != NULL && node->getType() != kHLNodeTypeFunc);

    error = context.serialize(assembler, start, node);
    context.cleanup();

    if (error != kErrorOk)
      break;
  } while (node != NULL);

  reset(false);
  return error;
}
示例#3
0
void Compiler::removeNodes(HLNode* first, HLNode* last) noexcept {
  if (first == last) {
    removeNode(first);
    return;
  }

  HLNode* prev = first->_prev;
  HLNode* next = last->_next;

  if (_firstNode == first)
    _firstNode = next;
  else
    prev->_next = next;

  if (_lastNode == last)
    _lastNode  = prev;
  else
    next->_prev = prev;

  HLNode* node = first;
  for (;;) {
    HLNode* next = node->getNext();
    ASMJIT_ASSERT(next != nullptr);

    node->_prev = nullptr;
    node->_next = nullptr;

    if (_cursor == node)
      _cursor = prev;
    Compiler_nodeRemoved(this, node);

    if (node == last)
      break;
    node = next;
  }
}
示例#4
0
Error Context::removeUnreachableCode() {
  Compiler* compiler = getCompiler();

  PodList<HLNode*>::Link* link = _unreachableList.getFirst();
  HLNode* stop = getStop();

  while (link != nullptr) {
    HLNode* node = link->getValue();
    if (node != nullptr && node->getPrev() != nullptr && node != stop) {
      // Locate all unreachable nodes.
      HLNode* first = node;
      do {
        if (node->isFetched())
          break;
        node = node->getNext();
      } while (node != stop);

      // Remove unreachable nodes that are neither informative nor directives.
      if (node != first) {
        HLNode* end = node;
        node = first;

        // NOTE: The strategy is as follows:
        // 1. The algorithm removes everything until it finds a first label.
        // 2. After the first label is found it removes only removable nodes.
        bool removeEverything = true;
        do {
          HLNode* next = node->getNext();
          bool remove = node->isRemovable();

          if (!remove) {
            if (node->isLabel())
              removeEverything = false;
            remove = removeEverything;
          }

          if (remove) {
            ASMJIT_TSEC({
              this->_traceNode(this, node, "[REMOVED UNREACHABLE] ");
            });
            compiler->removeNode(node);
          }

          node = next;
        } while (node != end);
      }
示例#5
0
Error Context::removeUnreachableCode() {
  Compiler* compiler = getCompiler();

  PodList<HLNode*>::Link* link = _unreachableList.getFirst();
  HLNode* stop = getStop();

  while (link != NULL) {
    HLNode* node = link->getValue();
    if (node != NULL && node->getPrev() != NULL && node != stop) {
      // Locate all unreachable nodes.
      HLNode* first = node;
      do {
        if (node->isFetched())
          break;
        node = node->getNext();
      } while (node != stop);

      // Remove unreachable nodes that are neither informative nor directives.
      if (node != first) {
        HLNode* end = node;
        node = first;
        do {
          HLNode* next = node->getNext();
          if (!node->isInformative() && node->getType() != kHLNodeTypeAlign) {
            ASMJIT_TLOG("[%05d] Unreachable\n", node->getFlowId());
            compiler->removeNode(node);
          }
          node = next;
        } while (node != end);
      }
    }

    link = link->getNext();
  }

  return kErrorOk;
}
示例#6
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);
}