reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
#include "OrcTestCommon.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LazyReexports.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace llvm::orc;

class LazyReexportsTest : public CoreAPIsBasedStandardTest {};

static int dummyTarget() { return 42; }

TEST_F(LazyReexportsTest, BasicLocalCallThroughManagerOperation) {
  // Create a callthrough manager for the host (if possible) and verify that
  // a call to the lazy call-through:
  // (1) Materializes the MU. This verifies that the symbol was looked up, and
  //     that we didn't arrive at the target via some other path
  // (2) Returns the expected value (which we take as proof that the call
  //     reached the target).

  auto JTMB = JITTargetMachineBuilder::detectHost();

  // Bail out if we can not detect the host.
  if (!JTMB) {
    consumeError(JTMB.takeError());
    return;
  }

  // Bail out if we can not build a local call-through manager.
  auto LCTM = createLocalLazyCallThroughManager(JTMB->getTargetTriple(), ES, 0);
  if (!LCTM) {
    consumeError(LCTM.takeError());
    return;
  }

  auto DummyTarget = ES.intern("DummyTarget");

  bool DummyTargetMaterialized = false;

  cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
      SymbolFlagsMap({{DummyTarget, JITSymbolFlags::Exported}}),
      [&](MaterializationResponsibility R) {
        DummyTargetMaterialized = true;
        // No dependencies registered, can't fail.
        cantFail(R.notifyResolved(
            {{DummyTarget,
              JITEvaluatedSymbol(static_cast<JITTargetAddress>(
                                     reinterpret_cast<uintptr_t>(&dummyTarget)),
                                 JITSymbolFlags::Exported)}}));
        cantFail(R.notifyEmitted());
      })));

  unsigned NotifyResolvedCount = 0;
  auto NotifyResolved = LazyCallThroughManager::createNotifyResolvedFunction(
      [&](JITDylib &JD, const SymbolStringPtr &SymbolName,
          JITTargetAddress ResolvedAddr) {
        ++NotifyResolvedCount;
        return Error::success();
      });

  auto CallThroughTrampoline = cantFail((*LCTM)->getCallThroughTrampoline(
      JD, DummyTarget, std::move(NotifyResolved)));

  auto CTTPtr = reinterpret_cast<int (*)()>(
      static_cast<uintptr_t>(CallThroughTrampoline));

  // Call twice to verify nothing unexpected happens on redundant calls.
  auto Result = CTTPtr();
  (void)CTTPtr();

  EXPECT_TRUE(DummyTargetMaterialized)
      << "CallThrough did not materialize target";
  EXPECT_EQ(NotifyResolvedCount, 1U)
      << "CallThrough should have generated exactly one 'NotifyResolved' call";
  EXPECT_EQ(Result, 42) << "Failed to call through to target";
}