Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/runtime/Component.h
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,8 @@ class Component {
friend class wabt::WASMComponentBinaryReader;

public:
static constexpr uint32_t MaxStringByteLength = 0x0fffffff;

struct InlineExport {
std::string name;
ComponentSort sort;
Expand Down
188 changes: 176 additions & 12 deletions src/runtime/ComponentInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,159 @@ namespace Walrus {

DEFINE_GLOBAL_TYPE_INFO(componentInstanceTypeInfo, ComponentInstanceKind);

LoweredFunction* LoweredFunction::createLoweredFunction(Store* store, const FunctionType* functionType, LiftedFunction* liftedFunction, CanonOptions* options)
static void throwException(ExecutionState& state, const char* message)
{
std::string stringMessage = message;
Trap::throwException(state, stringMessage);
}

void CanonOptions::memoryCheckRange32(ExecutionState& state, uint32_t align, uint32_t start, uint32_t size)
{
ASSERT(!memory()->is64() && align <= 8 && (align & (align - 1)) == 0);

align = start & (align - 1);
if (align == 0 && memory()->sizeInByte() >= size && memory()->sizeInByte() - size >= start) {
return;
}

throwException(state, align != 0 ? "incorrectly aligned memory area" : "out of bounds memory area");
}

void CanonOptions::memoryCheckRange64(ExecutionState& state, uint64_t align, uint64_t start, uint64_t size)
{
ASSERT(memory()->is64() && align <= 8 && (align & (align - 1)) == 0);

align = start & (align - 1);
if (align == 0 && memory()->sizeInByte() >= size && memory()->sizeInByte() - size >= start) {
return;
}

throwException(state, align != 0 ? "incorrectly aligned memory area" : "out of bounds memory area");
}

uint32_t CanonOptions::memoryMalloc32(ExecutionState& state, uint32_t align, uint32_t size)
{
ASSERT(!memory()->is64() && realloc() != nullptr && align <= 8 && (align & (align - 1)) == 0);

Value argv[4];
Value result;
argv[0] = Value(static_cast<int32_t>(0));
argv[1] = Value(static_cast<int32_t>(0));
argv[2] = Value(static_cast<int32_t>(align));
argv[3] = Value(static_cast<int32_t>(size));

// Should trap on an error (unreachable).
realloc()->call(state, argv, &result);
uint32_t start = static_cast<uint32_t>(result.asI32());
memoryCheckRange32(state, align, start, size);
return start;
}

uint64_t CanonOptions::memoryMalloc64(ExecutionState& state, uint64_t align, uint64_t size)
{
ASSERT(memory()->is64() && realloc() != nullptr && align <= 8 && (align & (align - 1)) == 0);

Value argv[4];
Value result;
argv[0] = Value(static_cast<int64_t>(0));
argv[1] = Value(static_cast<int64_t>(0));
argv[2] = Value(static_cast<int64_t>(align));
argv[3] = Value(static_cast<int64_t>(size));

// Should trap on an error (unreachable).
realloc()->call(state, argv, &result);
uint64_t start = static_cast<uint64_t>(result.asI64());
memoryCheckRange64(state, align, start, size);
return start;
}

enum Utf8Consts : uint8_t {
Utf8Len1Mask = 0x7f,
Utf8Len2 = 0xc0,
Utf8Len2Mask = 0x1f,
Utf8Cont = 0x80,
Utf8ContMask = 0x3f,
Utf8ContShift1 = 6,
Utf8ContShift2 = 12,
Utf8ContShift3 = 18,
};

uint64_t CanonOptions::storeLatin1String(ExecutionState& state, const uint8_t* src, uint32_t* length)
{
uint32_t codeUnitLength = *length;
uint32_t byteLength = codeUnitLength;
uint32_t align = 2;
const uint8_t* end = src + codeUnitLength;

switch (encoding()) {
case ComponentCanonOptions::Utf8:
align = 1;
for (const uint8_t* ptr = src; ptr < end; ptr++) {
if ((*ptr & ~Utf8Len1Mask) != 0) {
byteLength++;
}
}
*length = byteLength;
break;
case ComponentCanonOptions::Utf16:
byteLength <<= 1;
break;
default:
ASSERT(encoding() == ComponentCanonOptions::Latin1Utf16);
break;
}

if (byteLength > Component::MaxStringByteLength) {
throwException(state, "result string too large");
}

uint64_t start;
uint8_t* ptr;
if (memory()->is64()) {
start = memoryMalloc64(state, align, byteLength);
ptr = reinterpret_cast<uint8_t*>(memory()->buffer() + start);
} else {
uint32_t start32 = memoryMalloc32(state, align, byteLength);
ptr = reinterpret_cast<uint8_t*>(memory()->buffer() + start32);
start = start32;
}

switch (encoding()) {
case ComponentCanonOptions::Utf8:
if (byteLength == codeUnitLength) {
break;
}

while (src < end) {
if ((*src & ~Utf8Len1Mask) == 0) {
*ptr++ = *src;
} else {
ptr[0] = static_cast<uint8_t>(Utf8Len2 | (*src >> Utf8ContShift1));
ptr[1] = static_cast<uint8_t>(Utf8Cont | (*src & Utf8ContMask));
ptr += 2;
}
src++;
}
return start;
case ComponentCanonOptions::Utf16:
while (src < end) {
ptr[0] = *src++;
ptr[1] = 0;
ptr += 2;
}
return start;
default:
ASSERT(byteLength == codeUnitLength);
break;
}
memcpy(ptr, src, byteLength);
return start;
}

LoweredFunction* LoweredFunction::createLoweredFunction(const FunctionType* functionType, LiftedFunction* liftedFunction, CanonOptions* options)
{
LoweredFunction* func = new LoweredFunction(functionType, liftedFunction, options);
store->appendExtern(func);
options->instance()->store()->appendExtern(func);
return func;
}

Expand Down Expand Up @@ -84,9 +233,10 @@ void CanonFunction::call(ExecutionState& state, Value* argv, Value* result)
}
}

ComponentInstance::ComponentInstance(ComponentType* type)
ComponentInstance::ComponentInstance(Store* store, ComponentType* type)
: Object(GET_GLOBAL_TYPE_INFO(componentInstanceTypeInfo))
, m_type(type)
, m_store(store)
, m_freeResourceHandle(LastHandle)
{
type->addRef();
Expand Down Expand Up @@ -167,7 +317,7 @@ void ComponentInstance::throwInvalidHandle(ExecutionState& state, uint32_t index

ComponentInstance* ComponentInstance::createInstance(Store* store, ComponentType* type)
{
ComponentInstance* instance = new ComponentInstance(type);
ComponentInstance* instance = new ComponentInstance(store, type);
store->appendComponentInstance(instance);
return instance;
}
Expand Down Expand Up @@ -218,7 +368,7 @@ bool ComponentInstance::compareTypes(ComponentRefCounted* expected, ComponentRef
return true;
}

void ComponentInstance::coreInstantiate(ExecutionState& state, Store* store, Component* component, ComponentCoreInstantiate* instantiate)
void ComponentInstance::coreInstantiate(ExecutionState& state, Component* component, ComponentCoreInstantiate* instantiate)
{
ExternVector imports;
Module* module = component->modules()[instantiate->moduleIndex()];
Expand Down Expand Up @@ -487,24 +637,24 @@ void ComponentInstance::aliasInline(ComponentAliasInline* alias)
}
}

void ComponentInstance::liftFunction(Store* store, std::vector<CanonOptions*>& canonOptions, ComponentCanonLift* lift)
void ComponentInstance::liftFunction(std::vector<CanonOptions*>& canonOptions, ComponentCanonLift* lift)
{
CanonOptions* options = canonOptions[lift->options()];
m_funcs.push_back(new LiftedCoreFunction(m_coreFuncs[lift->coreFuncIndex()], options));
}

void ComponentInstance::lowerFunction(Store* store, std::vector<CanonOptions*>& canonOptions, ComponentCanonLower* lower)
void ComponentInstance::lowerFunction(std::vector<CanonOptions*>& canonOptions, ComponentCanonLower* lower)
{
LiftedFunction* func = m_funcs[lower->funcIndex()];
CanonOptions* options = canonOptions[lower->options()];

#ifdef ENABLE_WASI
if (func->kind() == LiftedFunction::WasiFunctionKind) {
m_coreFuncs.push_back(LoweredFunction::createLoweredFunction(store, getWasiFunctionType(func->asLiftedWasiFunction()), func, options));
m_coreFuncs.push_back(LoweredFunction::createLoweredFunction(getWasiFunctionType(func->asLiftedWasiFunction()), func, options));
return;
}
#endif /* ENABLE_WASI */
m_coreFuncs.push_back(LoweredFunction::createLoweredFunction(store, func->asLiftedCoreFunction()->function()->functionType(), func, options));
m_coreFuncs.push_back(LoweredFunction::createLoweredFunction(func->asLiftedCoreFunction()->function()->functionType(), func, options));
}

ComponentInstance* ComponentInstance::InstantiateContext::instantiate(Component* component, ComponentInstance* parent, ComponentInstantiate* arg)
Expand All @@ -516,7 +666,7 @@ ComponentInstance* ComponentInstance::InstantiateContext::instantiate(Component*
for (auto it : component->declarations()) {
switch (it->kind()) {
case ComponentDeclaration::CoreInstantiateKind: {
instance->coreInstantiate(m_state, m_store, component, it->asCoreInstantiate());
instance->coreInstantiate(m_state, component, it->asCoreInstantiate());
break;
}
case ComponentDeclaration::InstantiateKind: {
Expand All @@ -542,15 +692,29 @@ ComponentInstance* ComponentInstance::InstantiateContext::instantiate(Component*
Function* realloc = options->reallocIndex() == ComponentCanonOptions::NotDefined ? nullptr : instance->m_coreFuncs[options->reallocIndex()];
Function* postReturn = options->postReturnIndex() == ComponentCanonOptions::NotDefined ? nullptr : instance->m_coreFuncs[options->postReturnIndex()];
Function* callback = options->callbackIndex() == ComponentCanonOptions::NotDefined ? nullptr : instance->m_coreFuncs[options->callbackIndex()];

if (realloc != nullptr) {
ASSERT(memory != nullptr);
Value::Type type = memory->is64() ? Value::I64 : Value::I32;

const TypeVector::Types& param = realloc->functionType()->param().types();
const TypeVector::Types& result = realloc->functionType()->result().types();
if (param.size() != 4 || param[0] != type || param[1] != type || param[2] != type || param[3] != type
|| result.size() != 1 || result[0] != type) {
std::string message = "invalid realloc function";
Trap::throwException(m_state, message);
}
}

instance->m_canonOptions.push_back(new CanonOptions(instance, options->encoding(), options->isAsync(), memory, realloc, postReturn, callback));
break;
}
case ComponentDeclaration::CanonLiftKind: {
instance->liftFunction(m_store, instance->m_canonOptions, it->asCanonLift());
instance->liftFunction(instance->m_canonOptions, it->asCanonLift());
break;
}
case ComponentDeclaration::CanonLowerKind: {
instance->lowerFunction(m_store, instance->m_canonOptions, it->asCanonLower());
instance->lowerFunction(instance->m_canonOptions, it->asCanonLower());
break;
}
case ComponentDeclaration::CanonResourceDrop: {
Expand Down
25 changes: 20 additions & 5 deletions src/runtime/ComponentInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class ComponentInstance;

class CanonOptions {
public:
static constexpr uint32_t Utf16Tag = static_cast<uint32_t>(1) << 31;

CanonOptions(ComponentInstance* instance, ComponentCanonOptions::StringEncoding encoding, bool isAsync,
Memory* memory, Function* realloc, Function* postReturn, Function* callback)
: m_instance(instance)
Expand Down Expand Up @@ -73,6 +75,13 @@ class CanonOptions {
return m_callback;
}

void memoryCheckRange32(ExecutionState& state, uint32_t align, uint32_t start, uint32_t size);
void memoryCheckRange64(ExecutionState& state, uint64_t align, uint64_t start, uint64_t size);
uint32_t memoryMalloc32(ExecutionState& state, uint32_t align, uint32_t size);
uint64_t memoryMalloc64(ExecutionState& state, uint64_t align, uint64_t size);

uint64_t storeLatin1String(ExecutionState& state, const uint8_t* src, uint32_t* length);

private:
ComponentInstance* m_instance;
ComponentCanonOptions::StringEncoding m_encoding;
Expand Down Expand Up @@ -169,7 +178,7 @@ class LiftedCoreFunction : public LiftedFunction {

class LoweredFunction : public NativeFunction {
public:
static LoweredFunction* createLoweredFunction(Store* store, const FunctionType* functionType, LiftedFunction* liftedFunction, CanonOptions* options);
static LoweredFunction* createLoweredFunction(const FunctionType* functionType, LiftedFunction* liftedFunction, CanonOptions* options);

virtual Kind kind() const override
{
Expand Down Expand Up @@ -346,6 +355,11 @@ class ComponentInstance : public Object {
return m_type;
}

Store* store()
{
return m_store;
}

LiftedFunction* getFunction(uint32_t index)
{
return m_funcs[index];
Expand All @@ -370,7 +384,7 @@ class ComponentInstance : public Object {
}

private:
ComponentInstance(ComponentType* type);
ComponentInstance(Store* store, ComponentType* type);

class InstantiateContext {
public:
Expand All @@ -396,14 +410,15 @@ class ComponentInstance : public Object {
static ComponentInstance* createInstance(Store* store, ComponentType* type);

static bool compareTypes(ComponentRefCounted* expected, ComponentRefCounted* provided, std::vector<ComponentRefCounted*>& resources);
void coreInstantiate(ExecutionState& state, Store* store, Component* component, ComponentCoreInstantiate* instantiate);
void coreInstantiate(ExecutionState& state, Component* component, ComponentCoreInstantiate* instantiate);
void aliasExport(ComponentAliasExport* alias);
void aliasCoreExport(ComponentAliasExport* alias);
void aliasInline(ComponentAliasInline* alias);
void liftFunction(Store* store, std::vector<CanonOptions*>& canonOptions, ComponentCanonLift* lift);
void lowerFunction(Store* store, std::vector<CanonOptions*>& canonOptions, ComponentCanonLower* lower);
void liftFunction(std::vector<CanonOptions*>& canonOptions, ComponentCanonLift* lift);
void lowerFunction(std::vector<CanonOptions*>& canonOptions, ComponentCanonLower* lower);

ComponentType* m_type;
Store* m_store;
uintptr_t m_freeResourceHandle;
std::vector<Function*> m_coreFuncs;
std::vector<Table*> m_coreTables;
Expand Down
2 changes: 2 additions & 0 deletions src/runtime/Memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Memory : public Extern {
public:
static const uint32_t s_memoryPageSize = 1024 * 64;
static const uint64_t s_maxMemory64Grow = ~static_cast<uint64_t>(0) / s_memoryPageSize;
static const uint64_t s_maxMemory64 = ~static_cast<uint64_t>(0);
static const uint32_t s_maxMemory32 = ~static_cast<uint32_t>(0);

// Caching memory target for fast access.
struct TargetBuffer {
Expand Down
19 changes: 3 additions & 16 deletions src/runtime/Store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ static const FunctionType g_defaultFunctionTypes[] = {

Store::Store(Engine* engine)
: m_engine(engine)
#ifdef ENABLE_WASI
, m_wasiData(nullptr)
#endif
{
memset(m_definedFuncTypes, 0, sizeof(m_definedFuncTypes));
#ifdef ENABLE_GC
Expand Down Expand Up @@ -117,22 +120,6 @@ Waiter* Store::getWaiter(void* address)
return waiter;
}

#ifdef ENABLE_WASI
void Store::registerWasiComponentInstance(size_t instanceId, ComponentInstance* instance)
{
m_wasiInstances[instanceId] = instance;
}

ComponentInstance* Store::findWasiComponentInstance(size_t instanceId)
{
auto it = m_wasiInstances.find(instanceId);
if (it == m_wasiInstances.end()) {
return nullptr;
}
return it->second;
}
#endif

FunctionType* Store::createDefinedFunctionType(DefinedFunctionType type)
{
const CompositeType** noIndex = reinterpret_cast<const CompositeType**>(TypeStore::NoIndex);
Expand Down
Loading
Loading