7#include "storage/Store.hpp"
15#include <libplatform/libplatform.h>
29#include <unordered_set>
39using args_t = v8::Local<v8::Value>[];
47int wasm_optimization_level = 0;
49bool wasm_adaptive =
false;
51bool wasm_compilation_cache =
true;
53bool wasm_dump =
false;
70 friend void create_V8Engine();
71 friend void destroy_V8Engine();
72 friend void register_WasmV8();
75 static inline v8::Platform *PLATFORM_ =
nullptr;
76 v8::ArrayBuffer::Allocator *allocator_ =
nullptr;
77 v8::Isolate *isolate_ =
nullptr;
80 std::unique_ptr<V8InspectorClientImpl> inspector_;
84 V8Engine(
const V8Engine&) =
delete;
85 V8Engine(V8Engine&&) =
default;
89 static v8::Platform * platform() {
104inline v8::Local<v8::String> to_v8_string(v8::Isolate *isolate, std::string_view sv) {
106 return v8::String::NewFromUtf8(isolate, sv.data(), v8::NewStringType::kNormal, sv.length()).ToLocalChecked();
109inline std::string to_std_string(v8::Isolate *isolate, v8::Local<v8::Value> val) {
110 v8::String::Utf8Value utf8(isolate, val);
114inline v8::Local<v8::Object> parse_json(v8::Isolate *isolate, std::string_view json) {
116 auto Ctx = isolate->GetCurrentContext();
117 auto value = v8::JSON::Parse(Ctx, to_v8_string(isolate, json)).ToLocalChecked();
119 return v8::Local<v8::Object>();
120 return value->ToObject(Ctx).ToLocalChecked();
123inline v8_inspector::StringView make_string_view(
const std::string &str) {
124 return v8_inspector::StringView(
reinterpret_cast<const uint8_t*
>(str.data()), str.length());
127inline std::string to_std_string(v8::Isolate *isolate,
const v8_inspector::StringView sv) {
128 int length =
static_cast<int>(sv.length());
129 v8::Local<v8::String> message = (
131 ? v8::String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*
>(sv.characters8()), v8::NewStringType::kNormal, length)
132 : v8::String::NewFromTwoByte(isolate, reinterpret_cast<const uint16_t*>(sv.characters16()), v8::NewStringType::kNormal, length)
134 v8::String::Utf8Value result(isolate, message);
135 return std::string(*result, result.length());
142 v8::HandleScope handle_scope(
isolate_);
143 auto str = to_std_string(
isolate_, message->string());
149 v8::HandleScope handle_scope(
isolate_);
150 auto str = to_std_string(
isolate_, message->string());
158 std::cout <<
"Initiating the V8 inspector server. To attach to the inspector, open Chrome/Chromium and "
160 "devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:"
161 << port <<
'\n' << std::endl;
163 inspector_ = v8_inspector::V8Inspector::create(isolate,
this);
168 std::string state(
"mutable");
172 make_string_view(state),
173 v8_inspector::V8Inspector::kFullyTrusted,
174 v8_inspector::V8Inspector::kWaitingForDebugger
180 std::string ctx_name(
"query");
181 inspector_->contextCreated(v8_inspector::V8ContextInfo( context, 1, make_string_view(ctx_name)));
191 v8_inspector::StringView msg(
reinterpret_cast<const uint8_t*
>(sv.data()), sv.length());
193 auto Ctx =
isolate_->GetCurrentContext();
194 v8::HandleScope handle_scope(
isolate_);
195 auto obj = parse_json(
isolate_, sv);
197 session_->dispatchProtocolMessage(msg);
199 if (not obj.IsEmpty()) {
200 auto method = obj->Get(Ctx, to_v8_string(
isolate_,
"method")).ToLocalChecked();
201 auto method_name = to_std_string(
isolate_, method);
203 if (method_name ==
"Runtime.runIfWaitingForDebugger") {
204 std::string reason(
"CDT");
205 session_->schedulePauseOnNextStatement(make_string_view(reason),
206 make_string_view(reason));
215 static bool is_nested =
false;
216 if (is_nested)
return;
221 while (v8::platform::PumpMessageLoop(V8Engine::platform(),
isolate_)) { }
236 auto idx = info[0].As<v8::BigInt>()->Uint64Value();
240 std::cerr << filename <<
':' << line <<
": Wasm_insist failed.";
242 std::cerr <<
" " << msg <<
'.';
243 std::cerr << std::endl;
252 auto idx = info[1].As<v8::BigInt>()->Uint64Value();
255 std::ostringstream oss;
258 oss <<
" " << msg <<
'.';
265 std::cerr << oss.str() << std::endl;
274 std::cout <<
"v8 function callback: ";
276 for (
int i = 0; i != info.Length(); ++i) {
277 v8::HandleScope handle_scope(info.GetIsolate());
278 if (i != 0) std::cout <<
',';
279 v8::Local<v8::Value> v = info[i];
281 std::cout <<
"0x" << std::hex << uint32_t(v.As<v8::Int32>()->Value()) << std::dec;
283 std::cout << *v8::String::Utf8Value(info.GetIsolate(), v);
285 std::cout << std::endl;
292 auto alloc_total_mem = info[0].As<v8::Uint32>()->
Value();
293 auto alloc_peak_mem = info[1].As<v8::Uint32>()->
Value();
295 std::cout <<
"Allocated memory overall consumption: " << alloc_total_mem / (1024.0 * 1024.0) <<
" MiB"<< std::endl;
296 std::cout <<
"Allocated memory peak consumption: " << alloc_peak_mem / (1024.0 * 1024.0) <<
" MiB"<< std::endl;
301 v8::Local<v8::WasmModuleObject> wasm_instance = info[0].As<v8::WasmModuleObject>();
302 v8::Local<v8::Int32> wasm_context_id = info[1].As<v8::Int32>();
306 std::cerr <<
"Setting Wasm instance raw memory of the given instance to the VM of Wasm context "
307 << wasm_context_id->Value() <<
" at " << wasm_context.vm.addr() <<
" of " << wasm_context.vm.size()
308 <<
" bytes" << std::endl;
310 v8::SetWasmInstanceRawMemory(wasm_instance, wasm_context.vm.as<uint8_t*>(), wasm_context.vm.size());
317 auto &root_op = context.plan.get_matched_root();
318 auto &schema = root_op.schema();
319 auto deduplicated_schema = schema.deduplicate();
320 auto deduplicated_schema_without_constants = deduplicated_schema.drop_constants();
323 auto num_tuples = info[1].As<v8::Uint32>()->
Value();
329 auto result_set_offset = info[0].As<v8::Uint32>()->
Value();
330 M_insist((result_set_offset == 0) == (deduplicated_schema_without_constants.num_entries() == 0),
331 "result set offset equals 0 (i.e. nullptr) iff schema contains only constants");
332 auto result_set = context.vm.as<uint8_t*>() + result_set_offset;
337 if (
auto projection_op = cast<const ProjectionOperator>(&
op)) {
338 return projection_op;
339 }
else if (
auto c = cast<const Consumer>(&
op)) {
341 "at least one projection without siblings in the operator tree must be contained");
342 M_insist(c->schema().num_entries() == c->child(0)->schema().num_entries(),
343 "at least one projection with the same schema as the plan's root must be contained");
345 for (std::size_t i = 0; i < c->schema().num_entries(); ++i)
346 M_insist(c->schema()[i].id == c->child(0)->schema()[i].id,
347 "at least one projection with the same schema as the plan's root must be contained");
349 return find_projection_ref(*c->child(0), find_projection_ref);
354 return find_projection_impl(
op, find_projection_impl);
356 auto projection = find_projection(root_op);
359 auto print_constant = [](std::ostringstream &out,
const ast::Constant &c,
const Type *type){
360 if (type->is_none()) {
366 auto value = Interpreter::eval(c);
369 [&](
const Boolean&) { out << (
value.as_b() ?
"TRUE" :
"FALSE"); },
373 case Numeric::N_Decimal:
376 case Numeric::N_Float:
377 if (
n.size() <= 32) {
378 const auto old_precision = out.precision(std::numeric_limits<float>::max_digits10 - 1);
380 out.precision(old_precision);
382 const auto old_precision = out.precision(std::numeric_limits<double>::max_digits10 - 1);
384 out.precision(old_precision);
390 const int32_t date =
value.as_i();
391 const auto oldfill = out.fill(
'0');
392 const auto oldfmt = out.flags();
394 << std::setw(date >> 9 > 0 ? 4 : 5) << (date >> 9) <<
'-'
395 << std::setw(2) << ((date >> 5) & 0xF) <<
'-'
396 << std::setw(2) << (date & 0x1F);
401 const time_t time =
value.as_i();
403 gmtime_r(&time, &tm);
411 if (deduplicated_schema_without_constants.num_entries() == 0) {
413 M_insist(
bool(projection),
"projection must be found");
414 auto &projections = projection->projections();
415 if (
auto callback_op = cast<const CallbackOperator>(&root_op)) {
417 for (std::size_t i = 0; i < schema.num_entries(); ++i) {
419 if (e.type->is_none())
continue;
421 tup.
set(i, Interpreter::eval(as<const ast::Constant>(projections[i].first)));
423 for (std::size_t i = 0; i < num_tuples; ++i)
424 callback_op->callback()(schema, tup);
425 }
else if (
auto print_op = cast<const PrintOperator>(&root_op)) {
426 std::ostringstream tup;
427 for (std::size_t i = 0; i < schema.num_entries(); ++i) {
432 print_constant(tup, as<const ast::Constant>(projections[i].first), e.type);
434 for (std::size_t i = 0; i < num_tuples; ++i)
435 print_op->out << tup.str() <<
'\n';
441 M_insist(
bool(context.result_set_factory),
"result set factory must be set");
442 auto layout = context.result_set_factory->make(deduplicated_schema_without_constants);
445 if (
auto callback_op = cast<const CallbackOperator>(&root_op)) {
447 deduplicated_schema_without_constants);
448 if (schema.num_entries() == deduplicated_schema.num_entries()) {
450 M_insist(schema == deduplicated_schema);
452 for (std::size_t i = 0; i < schema.num_entries(); ++i) {
454 if (e.type->is_none())
continue;
455 if (e.id.is_constant()) {
456 M_insist(
bool(projection),
"projection must be found");
457 tup.
set(i, Interpreter::eval(as<const ast::Constant>(projection->projections()[i].first)));
461 for (std::size_t i = 0; i != num_tuples; ++i) {
463 callback_op->callback()(schema, tup);
468 Tuple tup_dedupl(deduplicated_schema_without_constants);
469 Tuple tup_dupl(schema);
470 for (std::size_t i = 0; i < schema.num_entries(); ++i) {
472 if (e.type->is_none())
continue;
473 if (e.id.is_constant()) {
474 M_insist(
bool(projection),
"projection must be found");
475 tup_dupl.
set(i, Interpreter::eval(as<const ast::Constant>(projection->projections()[i].first)));
478 Tuple *
args[] = { &tup_dedupl, &tup_dupl };
479 for (std::size_t i = 0; i != deduplicated_schema_without_constants.num_entries(); ++i) {
480 auto &entry = deduplicated_schema_without_constants[i];
481 if (not entry.type->is_none())
482 loader.emit_Ld_Tup(0, i);
483 for (std::size_t j = 0; j != schema.num_entries(); ++j) {
485 if (e.id == entry.id) {
487 loader.emit_St_Tup(1, j, e.type);
490 if (not entry.type->is_none())
493 for (std::size_t i = 0; i != num_tuples; ++i) {
495 callback_op->callback()(schema, tup_dupl);
498 }
else if (
auto print_op = cast<const PrintOperator>(&root_op)) {
500 Tuple tup(deduplicated_schema_without_constants);
503 deduplicated_schema_without_constants);
504 auto ostream_index = printer.add(&print_op->out);
505 bool constant_emitted =
false;
506 std::size_t old_idx = -1UL;
507 for (std::size_t i = 0; i != schema.num_entries(); ++i) {
509 printer.emit_Putc(ostream_index,
',');
511 if (not e.type->is_none()) {
512 if (e.id.is_constant()) {
513 M_insist(
bool(projection),
"projection must be found");
514 printer.add_and_emit_load(Interpreter::eval(as<const ast::Constant>(projection->projections()[i].first)));
515 constant_emitted =
true;
517 auto idx = deduplicated_schema_without_constants[e.id].first;
518 if (idx != old_idx) {
521 printer.emit_Ld_Tup(0, idx);
526 printer.emit_Print(ostream_index, e.type);
527 if (e.type->is_none() or constant_emitted) {
529 constant_emitted =
false;
534 for (std::size_t i = 0; i != num_tuples; ++i) {
536 print_op->out <<
'\n';
541template<
typename Index,
typename V8ValueT,
bool IsLower>
544 using key_type = Index::key_type;
547 auto index_id = info[0].As<v8::BigInt>()->Uint64Value();
549 if constexpr (std::same_as<V8ValueT, v8::BigInt>)
550 key = info[1].As<V8ValueT>()->Int64Value();
551 else if constexpr (std::same_as<V8ValueT, v8::String>) {
552 auto offset = info[1].As<v8::Uint32>()->
Value();
554 key =
reinterpret_cast<const char*
>(context.vm.as<uint8_t*>() + offset);
556 key = info[1].As<V8ValueT>()->
Value();
560 auto &index = as<const Index>(context.indexes[index_id]);
563 std::size_t offset = std::distance(
567 M_insist(std::in_range<uint32_t>(offset),
"should fit in uint32_t");
568 info.GetReturnValue().Set(uint32_t(offset));
571template<
typename Index>
575 auto index_id = info[0].As<v8::BigInt>()->Uint64Value();
576 auto entry_offset = info[1].As<v8::Uint32>()->
Value();
577 auto address_offset = info[2].As<v8::Uint32>()->
Value();
578 auto batch_size = info[3].As<v8::Uint32>()->
Value();
582 auto buffer_address =
reinterpret_cast<uint32_t*
>(context.vm.as<uint8_t*>() + address_offset);
585 auto &index = as<const Index>(context.indexes[index_id]);
588 auto it = index.begin() + entry_offset;
589 for (uint32_t i = 0; i < batch_size; ++i, ++it)
590 buffer_address[i] = it->second;
603 std::unordered_set<const char*> literals_;
606 static std::vector<const char*> Collect(
const Operator &plan) {
607 CollectStringLiterals CSL;
609 return { CSL.literals_.begin(), CSL.literals_.end() };
613 CollectStringLiterals() =
default;
615 using ConstOperatorVisitor::operator();
616 using ConstASTExprVisitor::operator();
629 (*this)(
op.filter());
633 (*this)(
op.filter());
637 (*this)(
op.predicate());
641 for (
auto &p :
op.projections())
642 (*this)(p.first.get());
647 for (
auto &[grp, alias] :
op.group_by())
655 void operator()(
const cnf::CNF &cnf) {
656 for (
auto &clause: cnf) {
657 for (
auto &pred: clause)
667 auto s = Interpreter::eval(e);
668 literals_.emplace(s.as<
const char*>());
682 uint64_t operator()(
const std::reference_wrapper<const Table> &r)
const {
684 return h((
const char*)(r.get().name()));
690 bool operator()(
const std::reference_wrapper<const Table> &first,
691 const std::reference_wrapper<const Table> &second)
const
693 return first.get().name() == second.get().name();
698 std::unordered_set<std::reference_wrapper<const Table>,
hash,
equal> tables_;
701 static std::vector<std::reference_wrapper<const Table>> Collect(
const Operator &plan) {
704 return { CT.tables_.begin(), CT.tables_.end() };
708 CollectTables() =
default;
710 using ConstOperatorVisitor::operator();
717 void operator()(
const ScanOperator &
op)
override { tables_.emplace(
op.store().table()); }
736V8Engine::V8Engine() { initialize(); }
748void V8Engine::initialize()
756 std::ostringstream flags;
757 flags <<
"--stack_size 1000000 ";
758 if (options::wasm_adaptive) {
762 <<
"--wasm-dynamic-tiering "
763 <<
"--wasm-lazy-compilation ";
765 flags <<
"--no-liftoff "
766 <<
"--no-wasm-lazy-compilation ";
768 if (not options::wasm_compilation_cache) {
769 flags <<
"--no-compilation-cache "
770 <<
"--no-wasm-native-module-cache-enabled ";
772 if (options::asm_dump) {
773 flags <<
"--code-comments "
776 if (options::cdt_port >= 1024) {
777 flags <<
"--wasm-bounds-checks "
778 <<
"--wasm-stack-checks "
783 <<
"--trace-wasm-instances "
786 flags <<
"--no-wasm-bounds-checks "
787 <<
"--no-wasm-stack-checks "
788 <<
"--wasm-simd-ssse3-codegen ";
790 v8::V8::SetFlagsFromString(flags.str().c_str());
792 v8::Isolate::CreateParams create_params;
793 create_params.array_buffer_allocator = allocator_ = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
794 isolate_ = v8::Isolate::New(create_params);
819 std::cout <<
"Pre-allocated memory overall consumption: "
821 <<
" MiB" << std::endl;
833 if (options::wasm_dump)
840 throw std::logic_error(
"invalid module");
846 std::ostringstream dump_before_opt;
849 if (options::wasm_optimization_level)
855 std::cerr <<
"Module invalid after optimization!" << std::endl;
856 std::cerr <<
"WebAssembly before optimization:\n" << dump_before_opt.str() << std::endl;
857 std::cerr <<
"WebAssembly after optimization:\n";
859 throw std::logic_error(
"invalid module");
871 M_insist(
bool(isolate_),
"must have an isolate");
872 v8::Locker locker(isolate_);
877 v8::Isolate::Scope isolate_scope(isolate_);
878 v8::HandleScope handle_scope(isolate_);
881 v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
883 global->Set(isolate_,
"read_result_set", v8::FunctionTemplate::New(isolate_,
read_result_set));
885#define CREATE_TEMPLATES(IDXTYPE, KEYTYPE, V8TYPE, IDXNAME, SUFFIX) \
886 global->Set(isolate_, M_STR(idx_lower_bound_##IDXNAME##_##SUFFIX), v8::FunctionTemplate::New(isolate_, index_seek<IDXTYPE<KEYTYPE>, V8TYPE, true>)); \
887 global->Set(isolate_, M_STR(idx_upper_bound_##IDXNAME##_##SUFFIX), v8::FunctionTemplate::New(isolate_, index_seek<IDXTYPE<KEYTYPE>, V8TYPE, false>)); \
888 global->Set(isolate_, M_STR(idx_scan_##IDXNAME##_##SUFFIX), v8::FunctionTemplate::New(isolate_, index_sequential_scan<IDXTYPE<KEYTYPE>>))
904#undef CREATE_TEMPLATES
906 v8::Local<v8::Context> context = v8::Context::New(isolate_,
nullptr, global);
907 v8::Context::Scope context_scope(context);
910 WasmContext::config_t wasm_config{0};
911 if (options::cdt_port < 1024)
912 wasm_config |= WasmContext::TRAP_GUARD_PAGES;
913 auto &wasm_context = Create_Wasm_Context_For_ID(
Module::ID(), plan, wasm_config);
915 auto imports = v8::Object::New(isolate_);
920 const auto bytes_remaining = wasm_context.vm.size() - wasm_context.heap;
922 mem.
map(bytes_remaining, 0, wasm_context.vm, wasm_context.heap);
929 M_DISCARD env->Set(isolate_->GetCurrentContext(), to_v8_string(isolate_,
"alloc_addr_init"),
931 M_DISCARD imports->Set(context,
mkstr(*isolate_,
"imports"), env);
937 v8::SetWasmInstanceRawMemory(instance, wasm_context.vm.as<uint8_t*>(), wasm_context.vm.size());
940 auto exports = instance->Get(context,
mkstr(*isolate_,
"exports")).ToLocalChecked().As<v8::Object>();
941 auto main = exports->Get(context,
mkstr(*isolate_,
"main")).ToLocalChecked().As<v8::Function>();
944 if (options::cdt_port >= 1024
and not inspector_)
945 inspector_ = std::make_unique<V8InspectorClientImpl>(options::cdt_port, isolate_);
946 if (
bool(inspector_)) {
952 args_t args { v8::Int32::New(isolate_, wasm_context.id), };
953 const uint32_t num_rows =
954 M_TIME_EXPR(
main->Call(context, context->Global(), 1,
args).ToLocalChecked().As<v8::Uint32>()->Value(),
955 "Execute machine code", C.
timer());
959 if (
auto print_op = cast<const PrintOperator>(&root_op)) {
961 print_op->out << num_rows <<
" rows\n";
962 }
else if (
auto noop_op = cast<const NoOpOperator>(&root_op)) {
964 noop_op->out << num_rows <<
" rows\n";
966 Dispose_Wasm_Context(wasm_context);
975static
void create_V8Engine()
977 V8Engine::PLATFORM_ = v8::platform::NewDefaultPlatform().release();
978 v8::V8::InitializePlatform(V8Engine::PLATFORM_);
979 v8::V8::SetFlagsFromString(
"--no-freeze-flags-after-init");
980 v8::V8::Initialize();
984static
void destroy_V8Engine()
987 v8::V8::DisposePlatform();
991static
void register_WasmV8()
1001 "set the optimization level for Wasm modules (0, 1, or 2)",
1002 [] (
int i) { options::wasm_optimization_level = i; }
1008 "enable adaptive execution of Wasm with Liftoff and dynamic tier-up",
1009 [] (
bool b) { options::wasm_adaptive = b; }
1014 "--no-wasm-compilation-cache",
1015 "disable V8's compilation cache",
1016 [] (
bool) { options::wasm_compilation_cache =
false; }
1022 "dump the generated WebAssembly code to stdout",
1023 [] (
bool b) { options::wasm_dump = b; }
1029 "dump the generated assembly code to stdout",
1030 [] (
bool b) { options::asm_dump = b; }
1036 "specify the port for debugging via ChromeDevTools",
1037 [] (
int i) { options::cdt_port = i; }
1050 return to_v8_string(&isolate, str);
1055 auto Ctx = isolate.GetCurrentContext();
1057 auto bs = v8::ArrayBuffer::NewBackingStore(
1060 v8::BackingStore::EmptyDeleter,
1063 auto buffer = v8::ArrayBuffer::New(&isolate, std::move(bs));
1066 std::cout <<
"Wasm code size: " << binary_size << std::endl;
1068 args_t module_args { buffer };
1069 auto wasm = Ctx->Global()->Get(Ctx,
mkstr(isolate,
"WebAssembly")).ToLocalChecked().As<v8::Object>();
1070 auto wasm_module =
wasm->Get(Ctx,
mkstr(isolate,
"Module")).ToLocalChecked().As<v8::Object>()
1071 ->CallAsConstructor(Ctx, 1, module_args).ToLocalChecked().As<v8::WasmModuleObject>();
1075 std::cout <<
"Machine code size: " << wasm_module->GetCompiledModule().Serialize().size << std::endl;
1077 args_t instance_args { wasm_module, imports };
1078 return wasm->Get(Ctx,
mkstr(isolate,
"Instance")).ToLocalChecked().As<v8::Object>()
1079 ->CallAsConstructor(Ctx, 2, instance_args).ToLocalChecked().As<v8::WasmModuleObject>();
1086 auto Ctx = isolate.GetCurrentContext();
1087 auto env = v8::Object::New(&isolate);
1091 for (
auto &table : tables) {
1092 auto off = context.map_table(table.get());
1095 std::ostringstream oss;
1096 oss << table.get().name() <<
"_mem";
1097 M_DISCARD env->Set(Ctx, to_v8_string(&isolate, oss.str()), v8::Int32::New(&isolate, off));
1102 oss << table.get().name() <<
"_num_rows";
1103 M_DISCARD env->Set(Ctx, to_v8_string(&isolate, oss.str()), v8::Int32::New(&isolate, table.get().store().num_rows()));
1110 for (
auto &attr : table.get()) {
1113 auto off = context.map_index(index);
1116 std::ostringstream oss;
1117 oss <<
"index_" << table.get().name() <<
'_' << attr.name <<
"_array" <<
"_mem";
1118 M_DISCARD env->Set(Ctx, to_v8_string(&isolate, oss.str()), v8::Int32::New(&isolate, off));
1123 oss <<
"index_" << table.get().name() <<
'_' << attr.name <<
"_array" <<
"_num_entries";
1124 M_DISCARD env->Set(Ctx, to_v8_string(&isolate, oss.str()), v8::Int32::New(&isolate, index.num_entries()));
1134 std::size_t bytes = 0;
1135 for (
auto literal : literals)
1136 bytes += strlen(literal) + 1;
1138 if (aligned_bytes) {
1139 auto base_addr = context.vm.as<uint8_t*>() + context.heap;
1140 M_DISCARD mmap(base_addr, aligned_bytes, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
1141 char *start_addr =
reinterpret_cast<char*
>(base_addr);
1142 char *dst = start_addr;
1143 for (
auto literal : literals) {
1145 dst = stpcpy(dst, literal) + 1;
1147 context.heap += aligned_bytes;
1148 context.install_guard_page();
1155#define EMIT_FUNC_IMPORTS(KEYTYPE, IDXNAME, SUFFIX) \
1156 Module::Get().emit_function_import<uint32_t(std::size_t,KEYTYPE)>(M_STR(idx_lower_bound_##IDXNAME##_##SUFFIX)); \
1157 Module::Get().emit_function_import<uint32_t(std::size_t,KEYTYPE)>(M_STR(idx_upper_bound_##IDXNAME##_##SUFFIX)); \
1158 Module::Get().emit_function_import<void(std::size_t,uint32_t,void*,uint32_t)>(M_STR(idx_scan_##IDXNAME##_##SUFFIX))
1174#undef EMIT_FUNC_IMPORTS
1176#define ADD_FUNC(FUNC, NAME) { \
1177 auto func = v8::Function::New(Ctx, (FUNC)).ToLocalChecked(); \
1178 env->Set(Ctx, mkstr(isolate, NAME), func).Check(); \
1180#define ADD_FUNC_(FUNC) ADD_FUNC(FUNC, #FUNC)
1187#define ADD_FUNCS(IDXTYPE, KEYTYPE, V8TYPE, IDXNAME, SUFFIX) \
1188 ADD_FUNC(index_seek<M_COMMA(IDXTYPE<KEYTYPE>) M_COMMA(V8TYPE) true>, M_STR(idx_lower_bound_##IDXNAME##_##SUFFIX)) \
1189 ADD_FUNC(index_seek<M_COMMA(IDXTYPE<KEYTYPE>) M_COMMA(V8TYPE) false>, M_STR(idx_upper_bound_##IDXNAME##_##SUFFIX)) \
1190 ADD_FUNC(index_sequential_scan<IDXTYPE<KEYTYPE>>, M_STR(idx_scan_##IDXNAME##_##SUFFIX))
1216 auto Ctx = isolate.GetCurrentContext();
1217 return v8::JSON::Stringify(Ctx, val).ToLocalChecked();
1223 std::ostringstream oss;
1227 auto json =
to_json(isolate, env);
1228 std::string env_str = *v8::String::Utf8Value(&isolate, json);
1229 if (env_str !=
"{}") env_str.insert(env_str.length() - 1,
",");
1230 env_str.insert(env_str.length() - 1,
"\"insist\": function (arg) { assert(arg); },");
1231 env_str.insert(env_str.length() - 1,
"\"print\": function (arg) { console.log(arg); },");
1232 env_str.insert(env_str.length() - 1,
"\"throw\": function (ex) { console.error(ex); },");
1233 env_str.insert(env_str.length() - 1,
"\"read_result_set\": read_result_set,");
1237let importObject = { \"imports\": " << env_str <<
" };\n\
1238const bytes = Uint8Array.from([";
1239 for (
auto p = binary_addr, end = p + binary_size; p != end; ++p) {
1240 if (p != binary_addr) oss <<
", ";
1241 oss << unsigned(*p);
1246WebAssembly.compile(bytes).then(\n\
1247 (module) => WebAssembly.instantiate(module, importObject),\n\
1248 (error) => console.error(`An error occurred during module compilation: ${error}`)\n\
1250 function(instance) {\n\
1251 set_wasm_instance_raw_memory(instance, " << wasm_context.
id <<
");\n\
1252 const num_tuples = instance.exports.main();\n\
1253 console.log('The result set contains %i tuples.', num_tuples);\n\
1256 (error) => console.error(`An error occurred during module instantiation: ${error}`)\n\
1261 const char *name =
"query.js";
1262 std::ofstream file(name, std::ios_base::out);
1265 std::cerr <<
"Creating debug JS script " << name << std::endl;
1276 return std::string(name);
1281 auto Ctx = isolate.GetCurrentContext();
1285 inspector.
start([&]() {
1289 std::ifstream js_in(filename);
1290 std::string js(std::istreambuf_iterator<char>(js_in), std::istreambuf_iterator<char>{});
1291 v8::Local<v8::String> js_src =
mkstr(isolate, js);
1292 std::string path = std::string(
"file://./") + filename;
1293 v8::ScriptOrigin js_origin = v8::ScriptOrigin(&isolate,
mkstr(isolate, path));
1294 auto script = v8::Script::Compile(Ctx, js_src, &js_origin);
1295 if (script.IsEmpty())
1296 throw std::runtime_error(
"failed to compile script");
1298 auto result = script.ToLocalChecked()->Run(Ctx);
1299 if (result.IsEmpty())
1300 throw std::runtime_error(
"execution failed");
__attribute__((constructor(202))) static void register_interpreter()
#define M_TIME_EXPR(EXPR, DESCR, TIMER)
#define EMIT_FUNC_IMPORTS(KEYTYPE, IDXNAME, SUFFIX)
#define ADD_FUNCS(IDXTYPE, KEYTYPE, V8TYPE, IDXNAME, SUFFIX)
#define CREATE_TEMPLATES(IDXTYPE, KEYTYPE, V8TYPE, IDXNAME, SUFFIX)
#define ADD_FUNC(FUNC, NAME)
#define FUNCTION(NAME, TYPE)
void add(const char *group_name, const char *short_name, const char *long_name, const char *description, Callback &&callback)
Adds a new group option to the ArgParser.
#define M_unreachable(MSG)
#define M_CONSTEXPR_COND(COND, IF_TRUE, IF_FALSE)
option_configs::IndexScanStrategy index_scan_strategy
Which index scan strategy should be used for wasm::IndexScan.
option_configs::IndexScanCompilationStrategy index_scan_compilation_strategy
Which compilation strategy should be used for wasm::IndexScan.
void insist(const v8::FunctionCallbackInfo< v8::Value > &info)
void _throw(const v8::FunctionCallbackInfo< v8::Value > &info)
v8::Local< v8::Object > create_env(v8::Isolate &isolate, const m::MatchBase &plan)
v8::Local< v8::WasmModuleObject > instantiate(v8::Isolate &isolate, v8::Local< v8::Object > imports)
std::string create_js_debug_script(v8::Isolate &isolate, v8::Local< v8::Object > env, const WasmEngine::WasmContext &wasm_context)
void print_memory_consumption(const v8::FunctionCallbackInfo< v8::Value > &info)
void set_wasm_instance_raw_memory(const v8::FunctionCallbackInfo< v8::Value > &info)
v8::Local< v8::String > mkstr(v8::Isolate &isolate, const std::string &str)
void index_sequential_scan(const v8::FunctionCallbackInfo< v8::Value > &info)
void run_inspector(V8InspectorClientImpl &inspector, v8::Isolate &isolate, v8::Local< v8::Object > env)
void print(const v8::FunctionCallbackInfo< v8::Value > &info)
void index_seek(const v8::FunctionCallbackInfo< v8::Value > &info)
v8::Local< v8::String > to_json(v8::Isolate &isolate, v8::Local< v8::Value > val)
void read_result_set(const v8::FunctionCallbackInfo< v8::Value > &info)
and
Constructs a new PrimitiveExpr from a constant value.
PrimitiveExpr< uint64_t, L > hash() and(L
bool M_EXPORT equal(const T &first, const U &second)
Checks whether first and second are equal considering permutations.
std::size_t Is_Page_Aligned(std::size_t n)
Returns true iff n is a integral multiple of the page size (in bytes).
std::function< void(void)> pipeline_t
std::size_t Ceil_To_Next_Page(std::size_t n)
Returns the smallest integral multiple of the page size (in bytes) greater than or equals to n.
auto visit(Callable &&callable, Base &obj, m::tag< Callable > &&=m::tag< Callable >())
Generic implementation to visit a class hierarchy, with similar syntax as std::visit.
command-line options for the HeuristicSearchPlanEnumerator
The catalog contains all Databases and keeps track of all meta information of the database system.
Database & get_database_in_use()
Returns a reference to the Database that is currently in use, if any.
void register_wasm_backend(ThreadSafePooledString name, const char *description=nullptr)
Registers a new WasmBackend using the given WasmEngine with the given name.
memory::Allocator & allocator()
Returns a reference to the memory::Allocator.
ThreadSafePooledString pool(const char *str) const
Creates an internalized copy of the string str by adding it to the internal StringPool.
static Catalog & Get()
Return a reference to the single Catalog instance.
Timer & timer()
Returns the global Timer instance.
m::ArgParser & arg_parser()
The type of character strings, both fixed length and varying length.
A Consumer is an Operator that can be evaluated on a sequence of tuples.
const std::vector< Producer * > & children() const
Returns a reference to the children of this Consumer.
static StackMachine compile_load(const Schema &tuple_schema, void *address, const storage::DataLayout &layout, const Schema &layout_schema, std::size_t row_id=0, std::size_t tuple_id=0)
Compile a StackMachine to load a tuple of Schema tuple_schema using a given memory address and a give...
virtual const Operator & get_matched_root() const =0
Returns the matched logical root operator for physical operators.
virtual void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const =0
Executes this physical operator match.
Drops the produced results and outputs only the number of result tuples produced.
A Type that represents the absence of any other type.
The numeric type represents integer and floating-point types of different precision and scale.
An Operator represents an operation in a query plan.
static Options & Get()
Return a reference to the single Options instance.
Prints the produced Tuples to a std::ostream instance.
Computes the FNV-1a 64-bit hash of a cstring.
TimingProcess create_timing(std::string name)
Creates a new TimingProcess with the given name.
void clear()
Sets all Values of this Tuple to NULL.
void set(std::size_t idx, Value val)
Assigns the Value val to this Tuple at index idx and clears the respective NULL bit.
This class represents types in the SQL type system.
This class holds a SQL attribute value.
A WasmContext holds associated information of a WebAssembly module instance.
A WasmEngine provides an environment to compile and execute WebAssembly modules.
virtual void execute(const MatchBase &plan)=0
Executes the already computed physical covering represented by plan using this WasmEngine.
static WasmContext & Get_Wasm_Context_By_ID(unsigned id)
Returns a reference to the WasmContext with ID id.
virtual void compile(const MatchBase &plan) const =0
Compiles the already computed physical covering represented by plan using this WasmEngine.
void send(std::string_view msg)
std::unique_ptr< Expr > lhs
std::unique_ptr< Expr > rhs
A constant: a string literal or a numeric constant.
A query expression for nested queries.
A unary expression: "+e", "-e", "~e", "NOT e".
std::unique_ptr< Expr > expr
A CNF represents a conjunction of cnf::Clauses.
A simple index based on a sorted array that maps keys to their tuple_id.
A recursive model index with two layers consiting only of linear monels that maps keys to their tuple...
virtual Memory allocate(std::size_t size)=0
Creates a new memory object with size bytes of freshly allocated memory.
Represents a mapping created by a memory::Allocator.
void map(std::size_t size, std::size_t offset_src, const AddressSpace &vm, std::size_t offset_dst) const
Map size bytes starting at offset_src into the address space of vm at offset offset_dst.
Signals a runtime error that mu*t*able is not responsible for and that mu*t*able was not able to reco...
static setup_t Make_Without_Parent(base_t &&callback=base_t())
static teardown_t Make_Without_Parent(base_t &&callback=base_t())
U32x1 num_tuples() const
Returns the number of result tuples produced.
void add_literal(const char *literal, uint32_t ptr)
Adds the string literal literal located at pointer offset ptr.
static CodeGenContext & Get()
Scope scoped_environment()
Creates a new, scoped Environment.
Represents a Wasm function.
void dump_all(std::ostream &out)
void emit_import(const char *extern_name, const char *intern_name=nullptr)
void emit_function_import(const char *name)
static bool Validate(bool verbose=true, bool global=true)
Validates that the module is well-formed.
void dump(std::ostream &out) const
static unsigned ID()
Returns the ID of the current module.
void emit_function_export(const char *name)
Add function name as export.
static void Optimize(int optimization_level)
Optimizes the module with the optimization level set to level.
void emit_call(const char *fn, PrimitiveExpr< ParamTypes, ParamLs >... args)
const std::tuple< const char *, unsigned, const char * > & get_message(std::size_t idx) const
std::pair< uint8_t *, std::size_t > binary()
Returns the binary representation of module_ in a freshly allocated memory.
std::unique_ptr< WebSocketServer::Connection > conn_
std::function< void(void)> code_
the code to execute in the debugger
void waitFrontendMessageOnPause()
void runMessageLoopOnPause(int) override
Synchronously consume all front end (CDT) debugging messages.
void register_context(v8::Local< v8::Context > context)
Register the context object in the V8Inspector instance.
std::unique_ptr< WebSocketChannel > channel_
std::unique_ptr< v8_inspector::V8InspectorSession > session_
V8InspectorClientImpl(int16_t port, v8::Isolate *isolate)
void on_message(std::string_view sv)
void start(std::function< void(void)> code)
void deregister_context(v8::Local< v8::Context > context)
Deregister the context object in the V8Inspector instance.
std::unique_ptr< v8_inspector::V8Inspector > inspector_
void sendResponse(int, std::unique_ptr< v8_inspector::StringBuffer > message) override
void sendNotification(std::unique_ptr< v8_inspector::StringBuffer > message) override
WebSocketServer::Connection & conn_
static constexpr const char *const names_[]