Commit 9c0617c3 by Antonio Maiorano

SubzeroReactor: add stubbed coroutine support

* Implement Nucleus::createCoroutine and acquireCoroutine so that they create a regular function for the Begin entry, and stubbed functions for the Await and Destroy entries. * Made Routine::getEntry const as Coroutine expects this function to be callable from multiple threads. Subzero's implementation would lazily finalize the entry and cache it. Now we finalize it eagerly in acquireRoutine, and getEntry simply returns pointers. Bug: b/130459196 Change-Id: Id9fa447ce55c7df6fb55e1c878ca021e825fecfa Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38873 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarBen Clayton <bclayton@google.com> Tested-by: 's avatarAntonio Maiorano <amaiorano@google.com>
parent b34b558a
......@@ -405,7 +405,7 @@ namespace
}
}
const void *getEntry(int index) override
const void *getEntry(int index) const override
{
return addresses[index];
}
......
......@@ -25,7 +25,7 @@ namespace rr
Routine() = default;
virtual ~Routine() = default;
virtual const void *getEntry(int index = 0) = 0;
virtual const void *getEntry(int index = 0) const = 0;
};
// RoutineT is a type-safe wrapper around a Routine and its callable entry, returned by FunctionT
......
......@@ -490,7 +490,7 @@ namespace rr
ELFMemoryStreamer &operator=(const ELFMemoryStreamer &) = delete;
public:
ELFMemoryStreamer() : Routine(), entry(nullptr)
ELFMemoryStreamer() : Routine()
{
position = 0;
buffer.reserve(0x1000);
......@@ -534,28 +534,35 @@ namespace rr
void seek(uint64_t Off) override { position = Off; }
const void *getEntry(int index) override
const void* finalizeEntryBegin()
{
ASSERT(index == 0); // Subzero does not support multiple entry points per routine yet.
if(!entry)
{
position = std::numeric_limits<std::size_t>::max(); // Can't stream more data after this
position = std::numeric_limits<std::size_t>::max(); // Can't stream more data after this
size_t codeSize = 0;
entry = loadImage(&buffer[0], codeSize);
#if defined(_WIN32)
VirtualProtect(&buffer[0], buffer.size(), PAGE_EXECUTE_READ, &oldProtection);
FlushInstructionCache(GetCurrentProcess(), NULL, 0);
#else
mprotect(&buffer[0], buffer.size(), PROT_READ | PROT_EXEC);
__builtin___clear_cache((char*)entry, (char*)entry + codeSize);
#endif
}
size_t codeSize = 0;
const void *entry = loadImage(&buffer[0], codeSize);
#if defined(_WIN32)
VirtualProtect(&buffer[0], buffer.size(), PAGE_EXECUTE_READ, &oldProtection);
FlushInstructionCache(GetCurrentProcess(), NULL, 0);
#else
mprotect(&buffer[0], buffer.size(), PROT_READ | PROT_EXEC);
__builtin___clear_cache((char*)entry, (char*)entry + codeSize);
#endif
return entry;
}
void setEntry(int index, const void* func)
{
ASSERT(func);
funcs[index] = func;
}
const void *getEntry(int index) const override
{
ASSERT(funcs[index]);
return funcs[index];
}
const void* addConstantData(const void* data, size_t size)
{
auto buf = std::unique_ptr<uint8_t[]>(new uint8_t[size]);
......@@ -566,7 +573,7 @@ namespace rr
}
private:
void *entry;
std::array<const void*, Nucleus::CoroutineEntryCount> funcs = {};
std::vector<uint8_t, ExecutableAllocator<uint8_t>> buffer;
std::size_t position;
std::vector<std::unique_ptr<uint8_t[]>> constantData;
......@@ -704,6 +711,9 @@ namespace rr
objectWriter->setUndefinedSyms(::context->getConstantExternSyms());
objectWriter->writeNonUserSections();
const void* entryBegin = ::routine->finalizeEntryBegin();
::routine->setEntry(Nucleus::CoroutineEntryBegin, entryBegin);
Routine *handoffRoutine = ::routine;
::routine = nullptr;
......@@ -3609,8 +3619,28 @@ namespace rr
void EmitDebugVariable(Value* value) {}
void FlushDebug() {}
void Nucleus::createCoroutine(Type *YieldType, std::vector<Type*> &Params) { UNIMPLEMENTED("createCoroutine"); }
std::shared_ptr<Routine> Nucleus::acquireCoroutine(const char *name, const Config::Edit &cfgEdit /* = Config::Edit::None */) { UNIMPLEMENTED("acquireCoroutine"); return nullptr; }
void Nucleus::createCoroutine(Type *YieldType, std::vector<Type*> &Params)
{
// Subzero currently only supports coroutines as functions (i.e. that do not yield)
createFunction(YieldType, Params);
}
static bool coroutineEntryAwaitStub(Nucleus::CoroutineHandle, void* yieldValue) { return false; }
static void coroutineEntryDestroyStub(Nucleus::CoroutineHandle) {}
std::shared_ptr<Routine> Nucleus::acquireCoroutine(const char *name, const Config::Edit &cfgEdit /* = Config::Edit::None */)
{
// acquireRoutine sets the CoroutineEntryBegin entry
auto coroutineEntry = acquireRoutine(name, cfgEdit);
// For now, set the await and destroy entries to stubs, until we add proper coroutine support to the Subzero backend
auto routine = std::static_pointer_cast<ELFMemoryStreamer>(coroutineEntry);
routine->setEntry(Nucleus::CoroutineEntryAwait, reinterpret_cast<const void*>(&coroutineEntryAwaitStub));
routine->setEntry(Nucleus::CoroutineEntryDestroy, reinterpret_cast<const void*>(&coroutineEntryDestroyStub));
return coroutineEntry;
}
void Nucleus::yield(Value* val) { UNIMPLEMENTED("Yield"); }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment