Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upstream WebAssembly VM and Null VM from envoyproxy/envoy-wasm. #8020

Merged
merged 32 commits into from
Sep 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3ffaa1d
Upstream WebAssembly VM and Null VM from envoyproxy/envoy-wasm.
jplevyak Aug 23, 2019
2efd035
Add WASM words to spelling dictionary.
jplevyak Aug 23, 2019
c8125e4
Address comments.
jplevyak Aug 23, 2019
c4387e6
Define and use WasmVmPtr
jplevyak Aug 23, 2019
375de9f
Cleanup some comments.
jplevyak Aug 23, 2019
87a4e5d
Remove unnecessary destructor override.
jplevyak Aug 23, 2019
b04b285
Address some tidy issues.
jplevyak Aug 24, 2019
630803a
Address comments.
jplevyak Aug 26, 2019
077335a
Add some doc comments.
jplevyak Aug 27, 2019
d4fb6b0
Add _ to u64 in Word.
jplevyak Aug 27, 2019
2a36aae
Fix formatting and spelling.
jplevyak Aug 27, 2019
9076aac
Fixup spelling.
jplevyak Aug 27, 2019
f31cdf4
Address comments.
jplevyak Aug 27, 2019
56c091a
Fix formatting.
jplevyak Aug 28, 2019
1a6a933
Use templates to define the WASM call and callout signatures.
jplevyak Aug 28, 2019
364f892
Address comments.
jplevyak Aug 28, 2019
2571fe3
Add more comments for emscripten.
jplevyak Aug 28, 2019
86db36f
Update comments.
jplevyak Aug 28, 2019
e9b546f
Fix case of paramaters.
jplevyak Aug 28, 2019
3726db9
Fix formatting.
jplevyak Aug 28, 2019
34c798b
Incorporate template comments.
jplevyak Aug 28, 2019
2b86403
Update debug_name doc comment.
jplevyak Aug 28, 2019
6928376
Update doc comments.
jplevyak Aug 28, 2019
58e2b8e
Update spelling.
jplevyak Aug 28, 2019
29cedee
Fix spelling error.
jplevyak Aug 29, 2019
0f796e4
Merge remote-tracking branch 'envoyproxy/master' into upstream-wasmvm
jplevyak Aug 29, 2019
81e029c
Add getWord and tests.
jplevyak Aug 29, 2019
39d61a8
Merge remote-tracking branch 'envoyproxy/master' into upstream-wasmvm
jplevyak Sep 5, 2019
ac6f651
Add more comments.
jplevyak Sep 5, 2019
5bae934
Add comments.
jplevyak Sep 5, 2019
b1d3593
Fix spelling.
jplevyak Sep 5, 2019
de85b21
Add comments.
jplevyak Sep 5, 2019
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 CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,5 @@ extensions/filters/common/original_src @snowp @klarose
/*/extensions/filters/listener/http_inspector @crazyxy @PiotrSikora @lizan
# attribute context
/*/extensions/filters/common/expr @kyessenov @yangminzhu
# webassembly common extension
/*/extensions/common/wasm @jplevyak @PiotrSikora
3 changes: 2 additions & 1 deletion source/common/common/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ namespace Logger {
FUNCTION(thrift) \
FUNCTION(tracing) \
FUNCTION(upstream) \
FUNCTION(udp)
FUNCTION(udp) \
FUNCTION(wasm)

enum class Id {
ALL_LOGGER_IDS(GENERATE_ENUM)
Expand Down
36 changes: 36 additions & 0 deletions source/extensions/common/wasm/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
licenses(["notice"]) # Apache 2

load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_library",
"envoy_package",
)

envoy_package()

envoy_cc_library(
name = "well_known_names",
hdrs = ["well_known_names.h"],
deps = [
"//source/common/singleton:const_singleton",
],
)

envoy_cc_library(
name = "wasm_vm_interface",
hdrs = ["wasm_vm.h"],
deps = [
":well_known_names",
"//source/common/common:minimal_logger_lib",
],
)

envoy_cc_library(
name = "wasm_vm_lib",
srcs = ["wasm_vm.cc"],
deps = [
":wasm_vm_interface",
"//source/common/common:assert_lib",
"//source/extensions/common/wasm/null:null_lib",
],
)
47 changes: 47 additions & 0 deletions source/extensions/common/wasm/null/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
licenses(["notice"]) # Apache 2

load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_library",
"envoy_package",
)

envoy_package()

envoy_cc_library(
name = "null_vm_plugin_interface",
hdrs = ["null_vm_plugin.h"],
deps = [
"//source/extensions/common/wasm:wasm_vm_interface",
"//source/extensions/common/wasm:well_known_names",
],
)

envoy_cc_library(
name = "null_vm_lib",
srcs = ["null_vm.cc"],
hdrs = ["null_vm.h"],
deps = [
":null_vm_plugin_interface",
"//external:abseil_node_hash_map",
"//include/envoy/registry",
"//source/common/common:assert_lib",
"//source/extensions/common/wasm:wasm_vm_interface",
"//source/extensions/common/wasm:well_known_names",
],
)

envoy_cc_library(
name = "null_lib",
srcs = ["null.cc"],
hdrs = ["null.h"],
deps = [
":null_vm_lib",
":null_vm_plugin_interface",
"//external:abseil_node_hash_map",
"//include/envoy/registry",
"//source/common/common:assert_lib",
"//source/extensions/common/wasm:wasm_vm_interface",
"//source/extensions/common/wasm:well_known_names",
],
)
27 changes: 27 additions & 0 deletions source/extensions/common/wasm/null/null.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "extensions/common/wasm/null/null.h"

#include <memory>
#include <utility>
#include <vector>

#include "envoy/registry/registry.h"

#include "common/common/assert.h"

#include "extensions/common/wasm/null/null_vm.h"
#include "extensions/common/wasm/null/null_vm_plugin.h"
#include "extensions/common/wasm/well_known_names.h"

namespace Envoy {
namespace Extensions {
namespace Common {
namespace Wasm {
namespace Null {

WasmVmPtr createVm() { return std::make_unique<NullVm>(); }

} // namespace Null
} // namespace Wasm
} // namespace Common
} // namespace Extensions
} // namespace Envoy
20 changes: 20 additions & 0 deletions source/extensions/common/wasm/null/null.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <memory>

#include "extensions/common/wasm/null/null_vm_plugin.h"
#include "extensions/common/wasm/wasm_vm.h"

namespace Envoy {
namespace Extensions {
namespace Common {
namespace Wasm {
namespace Null {

WasmVmPtr createVm();

} // namespace Null
} // namespace Wasm
} // namespace Common
} // namespace Extensions
} // namespace Envoy
104 changes: 104 additions & 0 deletions source/extensions/common/wasm/null/null_vm.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include "extensions/common/wasm/null/null_vm.h"

#include <memory>
#include <utility>
#include <vector>

#include "envoy/registry/registry.h"

#include "common/common/assert.h"

#include "extensions/common/wasm/null/null_vm_plugin.h"
#include "extensions/common/wasm/well_known_names.h"

namespace Envoy {
namespace Extensions {
namespace Common {
namespace Wasm {
namespace Null {

WasmVmPtr NullVm::clone() {
auto cloned_null_vm = std::make_unique<NullVm>(*this);
cloned_null_vm->load(plugin_name_, false /* unused */);
return cloned_null_vm;
}

// "Load" the plugin by obtaining a pointer to it from the factory.
bool NullVm::load(const std::string& name, bool /* allow_precompiled */) {
auto factory = Registry::FactoryRegistry<NullVmPluginFactory>::getFactory(name);
if (!factory) {
return false;
}
plugin_name_ = name;
plugin_ = factory->create();
return true;
}

void NullVm::link(absl::string_view /* name */, bool /* needs_emscripten */) {}

void NullVm::makeModule(absl::string_view /* name */) {
// NullVm does not advertise code as emscripten so this will not get called.
NOT_REACHED_GCOVR_EXCL_LINE;
}

void NullVm::start(Common::Wasm::Context* context) {
SaveRestoreContext saved_context(context);
plugin_->start();
}

uint64_t NullVm::getMemorySize() { return std::numeric_limits<uint64_t>::max(); }

// NulVm pointers are just native pointers.
absl::optional<absl::string_view> NullVm::getMemory(uint64_t pointer, uint64_t size) {
if (pointer == 0 && size != 0) {
return absl::nullopt;
}
return absl::string_view(reinterpret_cast<char*>(pointer), static_cast<size_t>(size));
}

bool NullVm::getMemoryOffset(void* host_pointer, uint64_t* vm_pointer) {
*vm_pointer = reinterpret_cast<uint64_t>(host_pointer);
return true;
}

bool NullVm::setMemory(uint64_t pointer, uint64_t size, const void* data) {
if ((pointer == 0 || data == nullptr)) {
if (size != 0) {
jplevyak marked this conversation as resolved.
Show resolved Hide resolved
return false;
} else {
return true;
}
}
auto p = reinterpret_cast<char*>(pointer);
memcpy(p, data, size);
return true;
}

bool NullVm::setWord(uint64_t pointer, Word data) {
if (pointer == 0) {
return false;
}
auto p = reinterpret_cast<char*>(pointer);
memcpy(p, &data.u64_, sizeof(data.u64_));
return true;
}

bool NullVm::getWord(uint64_t pointer, Word* data) {
if (pointer == 0) {
return false;
}
auto p = reinterpret_cast<char*>(pointer);
memcpy(&data->u64_, p, sizeof(data->u64_));
return true;
}

absl::string_view NullVm::getUserSection(absl::string_view /* name */) {
// Return nothing: there is no WASM file.
return {};
}

} // namespace Null
} // namespace Wasm
} // namespace Common
} // namespace Extensions
} // namespace Envoy
75 changes: 75 additions & 0 deletions source/extensions/common/wasm/null/null_vm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#pragma once

#include <memory>
#include <utility>
#include <vector>

#include "envoy/registry/registry.h"

#include "common/common/assert.h"

#include "extensions/common/wasm/null/null_vm_plugin.h"
#include "extensions/common/wasm/well_known_names.h"

namespace Envoy {
namespace Extensions {
namespace Common {
namespace Wasm {
namespace Null {

// The NullVm wraps a C++ WASM plugin which has been compiled with the WASM API
// and linked directly into the Envoy process. This is useful for development
// in that it permits the debugger to set breakpoints in both Envoy and the plugin.
struct NullVm : public WasmVm {
NullVm() = default;
mattklein123 marked this conversation as resolved.
Show resolved Hide resolved
NullVm(const NullVm& other) : plugin_name_(other.plugin_name_) {}

// WasmVm
absl::string_view vm() override { return WasmVmNames::get().Null; }
bool cloneable() override { return true; };
WasmVmPtr clone() override;
bool load(const std::string& code, bool allow_precompiled) override;
void link(absl::string_view debug_name, bool needs_emscripten) override;
void setMemoryLayout(uint64_t, uint64_t, uint64_t) override {}
void start(Common::Wasm::Context* context) override;
uint64_t getMemorySize() override;
absl::optional<absl::string_view> getMemory(uint64_t pointer, uint64_t size) override;
bool getMemoryOffset(void* host_pointer, uint64_t* vm_pointer) override;
bool setMemory(uint64_t pointer, uint64_t size, const void* data) override;
bool setWord(uint64_t pointer, Word data) override;
bool getWord(uint64_t pointer, Word* data) override;
void makeModule(absl::string_view name) override;
absl::string_view getUserSection(absl::string_view name) override;

#define _FORWARD_GET_FUNCTION(_T) \
void getFunction(absl::string_view function_name, _T* f) override { \
plugin_->getFunction(function_name, f); \
}
FOR_ALL_WASM_VM_EXPORTS(_FORWARD_GET_FUNCTION)
#undef _FORWARD_GET_FUNCTION

// These are not needed for NullVm which invokes the handlers directly.
#define _REGISTER_CALLBACK(_T) \
void registerCallback(absl::string_view, absl::string_view, _T, \
typename ConvertFunctionTypeWordToUint32<_T>::type) override{};
FOR_ALL_WASM_VM_IMPORTS(_REGISTER_CALLBACK)
#undef _REGISTER_CALLBACK

// NullVm does not advertise code as emscripten so this will not get called.
std::unique_ptr<Global<double>> makeGlobal(absl::string_view, absl::string_view,
double) override {
NOT_REACHED_GCOVR_EXCL_LINE;
};
std::unique_ptr<Global<Word>> makeGlobal(absl::string_view, absl::string_view, Word) override {
NOT_REACHED_GCOVR_EXCL_LINE;
};

std::string plugin_name_;
std::unique_ptr<NullVmPlugin> plugin_;
};

} // namespace Null
} // namespace Wasm
} // namespace Common
} // namespace Extensions
} // namespace Envoy
50 changes: 50 additions & 0 deletions source/extensions/common/wasm/null/null_vm_plugin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once

#include "extensions/common/wasm/wasm_vm.h"

namespace Envoy {
namespace Extensions {
namespace Common {
namespace Wasm {
namespace Null {

// A wrapper for the natively compiled NullVm plugin which implements the WASM ABI.
class NullVmPlugin {
public:
NullVmPlugin() = default;
virtual ~NullVmPlugin() = default;

// NB: These are defined rather than declared PURE because gmock uses __LINE__ internally for
// uniqueness, making it impossible to use FOR_ALL_WASM_VM_EXPORTS with MOCK_METHOD2.
#define _DEFINE_GET_FUNCTION(_T) \
virtual void getFunction(absl::string_view, _T* f) { *f = nullptr; }
FOR_ALL_WASM_VM_EXPORTS(_DEFINE_GET_FUNCTION)
#undef _DEFIN_GET_FUNCTIONE

virtual void start() PURE;
};

/**
* Pseudo-WASM plugins using the NullVM should implement this factory and register via
* Registry::registerFactory or the convenience class RegisterFactory.
*/
class NullVmPluginFactory {
public:
virtual ~NullVmPluginFactory() = default;

/**
* Name of the plugin.
*/
virtual const std::string name() const PURE;

/**
* Create an instance of the plugin.
*/
virtual std::unique_ptr<NullVmPlugin> create() const PURE;
};

} // namespace Null
} // namespace Wasm
} // namespace Common
} // namespace Extensions
} // namespace Envoy
Loading