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 <<
'.';
267 std::cout <<
"v8 function callback: ";
269 for (
int i = 0; i != info.Length(); ++i) {
270 v8::HandleScope handle_scope(info.GetIsolate());
271 if (i != 0) std::cout <<
',';
272 v8::Local<v8::Value> v = info[i];
274 std::cout <<
"0x" << std::hex << uint32_t(v.As<v8::Int32>()->Value()) << std::dec;
276 std::cout << *v8::String::Utf8Value(info.GetIsolate(), v);
278 std::cout << std::endl;
285 auto alloc_total_mem = info[0].As<v8::Uint32>()->
Value();
286 auto alloc_peak_mem = info[1].As<v8::Uint32>()->
Value();
288 std::cout <<
"Allocated memory overall consumption: " << alloc_total_mem / (1024.0 * 1024.0) <<
" MiB"<< std::endl;
289 std::cout <<
"Allocated memory peak consumption: " << alloc_peak_mem / (1024.0 * 1024.0) <<
" MiB"<< std::endl;
294 v8::Local<v8::WasmModuleObject> wasm_instance = info[0].As<v8::WasmModuleObject>();
295 v8::Local<v8::Int32> wasm_context_id = info[1].As<v8::Int32>();
299 std::cerr <<
"Setting Wasm instance raw memory of the given instance to the VM of Wasm context "
300 << wasm_context_id->Value() <<
" at " << wasm_context.vm.addr() <<
" of " << wasm_context.vm.size()
301 <<
" bytes" << std::endl;
303 v8::SetWasmInstanceRawMemory(wasm_instance, wasm_context.vm.as<uint8_t*>(), wasm_context.vm.size());
310 auto &root_op = context.plan.get_matched_root();
311 auto &schema = root_op.schema();
312 auto deduplicated_schema = schema.deduplicate();
313 auto deduplicated_schema_without_constants = deduplicated_schema.drop_constants();
316 auto num_tuples = info[1].As<v8::Uint32>()->
Value();
322 auto result_set_offset = info[0].As<v8::Uint32>()->
Value();
323 M_insist((result_set_offset == 0) == (deduplicated_schema_without_constants.num_entries() == 0),
324 "result set offset equals 0 (i.e. nullptr) iff schema contains only constants");
325 auto result_set = context.vm.as<uint8_t*>() + result_set_offset;
330 if (
auto projection_op = cast<const ProjectionOperator>(&
op)) {
331 return projection_op;
332 }
else if (
auto c = cast<const Consumer>(&
op)) {
334 "at least one projection without siblings in the operator tree must be contained");
335 M_insist(c->schema().num_entries() == c->child(0)->schema().num_entries(),
336 "at least one projection with the same schema as the plan's root must be contained");
338 for (std::size_t i = 0; i < c->schema().num_entries(); ++i)
339 M_insist(c->schema()[i].id == c->child(0)->schema()[i].id,
340 "at least one projection with the same schema as the plan's root must be contained");
342 return find_projection_ref(*c->child(0), find_projection_ref);
347 return find_projection_impl(
op, find_projection_impl);
349 auto projection = find_projection(root_op);
352 auto print_constant = [](std::ostringstream &out,
const ast::Constant &c,
const Type *type){
353 if (type->is_none()) {
359 auto value = Interpreter::eval(c);
362 [&](
const Boolean&) { out << (
value.as_b() ?
"TRUE" :
"FALSE"); },
366 case Numeric::N_Decimal:
369 case Numeric::N_Float:
370 if (
n.size() <= 32) {
371 const auto old_precision = out.precision(std::numeric_limits<float>::max_digits10 - 1);
373 out.precision(old_precision);
375 const auto old_precision = out.precision(std::numeric_limits<double>::max_digits10 - 1);
377 out.precision(old_precision);
383 const int32_t date =
value.as_i();
384 const auto oldfill = out.fill(
'0');
385 const auto oldfmt = out.flags();
387 << std::setw(date >> 9 > 0 ? 4 : 5) << (date >> 9) <<
'-'
388 << std::setw(2) << ((date >> 5) & 0xF) <<
'-'
389 << std::setw(2) << (date & 0x1F);
394 const time_t time =
value.as_i();
396 gmtime_r(&time, &tm);
404 if (deduplicated_schema_without_constants.num_entries() == 0) {
406 M_insist(
bool(projection),
"projection must be found");
407 auto &projections = projection->projections();
408 if (
auto callback_op = cast<const CallbackOperator>(&root_op)) {
410 for (std::size_t i = 0; i < schema.num_entries(); ++i) {
412 if (e.type->is_none())
continue;
414 tup.
set(i, Interpreter::eval(as<const ast::Constant>(projections[i].first)));
416 for (std::size_t i = 0; i < num_tuples; ++i)
417 callback_op->callback()(schema, tup);
418 }
else if (
auto print_op = cast<const PrintOperator>(&root_op)) {
419 std::ostringstream tup;
420 for (std::size_t i = 0; i < schema.num_entries(); ++i) {
425 print_constant(tup, as<const ast::Constant>(projections[i].first), e.type);
427 for (std::size_t i = 0; i < num_tuples; ++i)
428 print_op->out << tup.str() <<
'\n';
434 M_insist(
bool(context.result_set_factory),
"result set factory must be set");
435 auto layout = context.result_set_factory->make(deduplicated_schema_without_constants);
438 if (
auto callback_op = cast<const CallbackOperator>(&root_op)) {
440 deduplicated_schema_without_constants);
441 if (schema.num_entries() == deduplicated_schema.num_entries()) {
443 M_insist(schema == deduplicated_schema);
445 for (std::size_t i = 0; i < schema.num_entries(); ++i) {
447 if (e.type->is_none())
continue;
448 if (e.id.is_constant()) {
449 M_insist(
bool(projection),
"projection must be found");
450 tup.
set(i, Interpreter::eval(as<const ast::Constant>(projection->projections()[i].first)));
454 for (std::size_t i = 0; i != num_tuples; ++i) {
456 callback_op->callback()(schema, tup);
461 Tuple tup_dedupl(deduplicated_schema_without_constants);
462 Tuple tup_dupl(schema);
463 for (std::size_t i = 0; i < schema.num_entries(); ++i) {
465 if (e.type->is_none())
continue;
466 if (e.id.is_constant()) {
467 M_insist(
bool(projection),
"projection must be found");
468 tup_dupl.
set(i, Interpreter::eval(as<const ast::Constant>(projection->projections()[i].first)));
471 Tuple *
args[] = { &tup_dedupl, &tup_dupl };
472 for (std::size_t i = 0; i != deduplicated_schema_without_constants.num_entries(); ++i) {
473 auto &entry = deduplicated_schema_without_constants[i];
474 if (not entry.type->is_none())
475 loader.emit_Ld_Tup(0, i);
476 for (std::size_t j = 0; j != schema.num_entries(); ++j) {
478 if (e.id == entry.id) {
480 loader.emit_St_Tup(1, j, e.type);
483 if (not entry.type->is_none())
486 for (std::size_t i = 0; i != num_tuples; ++i) {
488 callback_op->callback()(schema, tup_dupl);
491 }
else if (
auto print_op = cast<const PrintOperator>(&root_op)) {
493 Tuple tup(deduplicated_schema_without_constants);
496 deduplicated_schema_without_constants);
497 auto ostream_index = printer.add(&print_op->out);
498 bool constant_emitted =
false;
499 std::size_t old_idx = -1UL;
500 for (std::size_t i = 0; i != schema.num_entries(); ++i) {
502 printer.emit_Putc(ostream_index,
',');
504 if (not e.type->is_none()) {
505 if (e.id.is_constant()) {
506 M_insist(
bool(projection),
"projection must be found");
507 printer.add_and_emit_load(Interpreter::eval(as<const ast::Constant>(projection->projections()[i].first)));
508 constant_emitted =
true;
510 auto idx = deduplicated_schema_without_constants[e.id].first;
511 if (idx != old_idx) {
514 printer.emit_Ld_Tup(0, idx);
519 printer.emit_Print(ostream_index, e.type);
520 if (e.type->is_none() or constant_emitted) {
522 constant_emitted =
false;
527 for (std::size_t i = 0; i != num_tuples; ++i) {
529 print_op->out <<
'\n';
534template<
typename Index,
typename V8ValueT,
bool IsLower>
537 using key_type = Index::key_type;
540 auto index_id = info[0].As<v8::BigInt>()->Uint64Value();
542 if constexpr (std::same_as<V8ValueT, v8::BigInt>)
543 key = info[1].As<V8ValueT>()->Int64Value();
544 else if constexpr (std::same_as<V8ValueT, v8::String>) {
545 auto offset = info[1].As<v8::Uint32>()->
Value();
547 key =
reinterpret_cast<const char*
>(context.vm.as<uint8_t*>() + offset);
549 key = info[1].As<V8ValueT>()->
Value();
553 auto &index = as<const Index>(context.indexes[index_id]);
556 std::size_t offset = std::distance(
560 M_insist(std::in_range<uint32_t>(offset),
"should fit in uint32_t");
561 info.GetReturnValue().Set(uint32_t(offset));
564template<
typename Index>
568 auto index_id = info[0].As<v8::BigInt>()->Uint64Value();
569 auto entry_offset = info[1].As<v8::Uint32>()->
Value();
570 auto address_offset = info[2].As<v8::Uint32>()->
Value();
571 auto batch_size = info[3].As<v8::Uint32>()->
Value();
575 auto buffer_address =
reinterpret_cast<uint32_t*
>(context.vm.as<uint8_t*>() + address_offset);
578 auto &index = as<const Index>(context.indexes[index_id]);
581 auto it = index.begin() + entry_offset;
582 for (uint32_t i = 0; i < batch_size; ++i, ++it)
583 buffer_address[i] = it->second;
596 std::unordered_set<const char*> literals_;
599 static std::vector<const char*> Collect(
const Operator &plan) {
600 CollectStringLiterals CSL;
602 return { CSL.literals_.begin(), CSL.literals_.end() };
606 CollectStringLiterals() =
default;
608 using ConstOperatorVisitor::operator();
609 using ConstASTExprVisitor::operator();
622 (*this)(
op.filter());
626 (*this)(
op.filter());
630 (*this)(
op.predicate());
634 for (
auto &p :
op.projections())
635 (*this)(p.first.get());
640 for (
auto &[grp, alias] :
op.group_by())
648 void operator()(
const cnf::CNF &cnf) {
649 for (
auto &clause: cnf) {
650 for (
auto &pred: clause)
660 auto s = Interpreter::eval(e);
661 literals_.emplace(s.as<
const char*>());
675 uint64_t operator()(
const std::reference_wrapper<const Table> &r)
const {
677 return h((
const char*)(r.get().name()));
683 bool operator()(
const std::reference_wrapper<const Table> &first,
684 const std::reference_wrapper<const Table> &second)
const
686 return first.get().name() == second.get().name();
691 std::unordered_set<std::reference_wrapper<const Table>,
hash,
equal> tables_;
694 static std::vector<std::reference_wrapper<const Table>> Collect(
const Operator &plan) {
697 return { CT.tables_.begin(), CT.tables_.end() };
701 CollectTables() =
default;
703 using ConstOperatorVisitor::operator();
710 void operator()(
const ScanOperator &
op)
override { tables_.emplace(
op.store().table()); }
729V8Engine::V8Engine() { initialize(); }
741void V8Engine::initialize()
749 std::ostringstream flags;
750 flags <<
"--stack_size 1000000 ";
751 if (options::wasm_adaptive) {
755 <<
"--wasm-dynamic-tiering "
756 <<
"--wasm-lazy-compilation ";
758 flags <<
"--no-liftoff "
759 <<
"--no-wasm-lazy-compilation ";
761 if (not options::wasm_compilation_cache) {
762 flags <<
"--no-compilation-cache "
763 <<
"--no-wasm-native-module-cache-enabled ";
765 if (options::asm_dump) {
766 flags <<
"--code-comments "
769 if (options::cdt_port >= 1024) {
770 flags <<
"--wasm-bounds-checks "
771 <<
"--wasm-stack-checks "
776 <<
"--trace-wasm-instances "
779 flags <<
"--no-wasm-bounds-checks "
780 <<
"--no-wasm-stack-checks "
781 <<
"--wasm-simd-ssse3-codegen ";
783 v8::V8::SetFlagsFromString(flags.str().c_str());
785 v8::Isolate::CreateParams create_params;
786 create_params.array_buffer_allocator = allocator_ = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
787 isolate_ = v8::Isolate::New(create_params);
812 std::cout <<
"Pre-allocated memory overall consumption: "
814 <<
" MiB" << std::endl;
826 if (options::wasm_dump)
833 throw std::logic_error(
"invalid module");
839 std::ostringstream dump_before_opt;
842 if (options::wasm_optimization_level)
848 std::cerr <<
"Module invalid after optimization!" << std::endl;
849 std::cerr <<
"WebAssembly before optimization:\n" << dump_before_opt.str() << std::endl;
850 std::cerr <<
"WebAssembly after optimization:\n";
852 throw std::logic_error(
"invalid module");
864 M_insist(
bool(isolate_),
"must have an isolate");
865 v8::Locker locker(isolate_);
870 v8::Isolate::Scope isolate_scope(isolate_);
871 v8::HandleScope handle_scope(isolate_);
874 v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
876 global->Set(isolate_,
"read_result_set", v8::FunctionTemplate::New(isolate_,
read_result_set));
878#define CREATE_TEMPLATES(IDXTYPE, KEYTYPE, V8TYPE, IDXNAME, SUFFIX) \
879 global->Set(isolate_, M_STR(idx_lower_bound_##IDXNAME##_##SUFFIX), v8::FunctionTemplate::New(isolate_, index_seek<IDXTYPE<KEYTYPE>, V8TYPE, true>)); \
880 global->Set(isolate_, M_STR(idx_upper_bound_##IDXNAME##_##SUFFIX), v8::FunctionTemplate::New(isolate_, index_seek<IDXTYPE<KEYTYPE>, V8TYPE, false>)); \
881 global->Set(isolate_, M_STR(idx_scan_##IDXNAME##_##SUFFIX), v8::FunctionTemplate::New(isolate_, index_sequential_scan<IDXTYPE<KEYTYPE>>))
897#undef CREATE_TEMPLATES
899 v8::Local<v8::Context> context = v8::Context::New(isolate_,
nullptr, global);
900 v8::Context::Scope context_scope(context);
903 WasmContext::config_t wasm_config{0};
904 if (options::cdt_port < 1024)
905 wasm_config |= WasmContext::TRAP_GUARD_PAGES;
906 auto &wasm_context = Create_Wasm_Context_For_ID(
Module::ID(), plan, wasm_config);
908 auto imports = v8::Object::New(isolate_);
913 const auto bytes_remaining = wasm_context.vm.size() - wasm_context.heap;
915 mem.
map(bytes_remaining, 0, wasm_context.vm, wasm_context.heap);
922 M_DISCARD env->Set(isolate_->GetCurrentContext(), to_v8_string(isolate_,
"alloc_addr_init"),
924 M_DISCARD imports->Set(context,
mkstr(*isolate_,
"imports"), env);
930 v8::SetWasmInstanceRawMemory(instance, wasm_context.vm.as<uint8_t*>(), wasm_context.vm.size());
933 auto exports = instance->Get(context,
mkstr(*isolate_,
"exports")).ToLocalChecked().As<v8::Object>();
934 auto main = exports->Get(context,
mkstr(*isolate_,
"main")).ToLocalChecked().As<v8::Function>();
937 if (options::cdt_port >= 1024
and not inspector_)
938 inspector_ = std::make_unique<V8InspectorClientImpl>(options::cdt_port, isolate_);
939 if (
bool(inspector_)) {
945 args_t args { v8::Int32::New(isolate_, wasm_context.id), };
946 const uint32_t num_rows =
947 M_TIME_EXPR(
main->Call(context, context->Global(), 1,
args).ToLocalChecked().As<v8::Uint32>()->Value(),
948 "Execute machine code", C.
timer());
952 if (
auto print_op = cast<const PrintOperator>(&root_op)) {
954 print_op->out << num_rows <<
" rows\n";
955 }
else if (
auto noop_op = cast<const NoOpOperator>(&root_op)) {
957 noop_op->out << num_rows <<
" rows\n";
959 Dispose_Wasm_Context(wasm_context);
968static
void create_V8Engine()
970 V8Engine::PLATFORM_ = v8::platform::NewDefaultPlatform().release();
971 v8::V8::InitializePlatform(V8Engine::PLATFORM_);
972 v8::V8::SetFlagsFromString(
"--no-freeze-flags-after-init");
973 v8::V8::Initialize();
977static
void destroy_V8Engine()
980 v8::V8::DisposePlatform();
984static
void register_WasmV8()
994 "set the optimization level for Wasm modules (0, 1, or 2)",
995 [] (
int i) { options::wasm_optimization_level = i; }
1001 "enable adaptive execution of Wasm with Liftoff and dynamic tier-up",
1002 [] (
bool b) { options::wasm_adaptive = b; }
1007 "--no-wasm-compilation-cache",
1008 "disable V8's compilation cache",
1009 [] (
bool) { options::wasm_compilation_cache =
false; }
1015 "dump the generated WebAssembly code to stdout",
1016 [] (
bool b) { options::wasm_dump = b; }
1022 "dump the generated assembly code to stdout",
1023 [] (
bool b) { options::asm_dump = b; }
1029 "specify the port for debugging via ChromeDevTools",
1030 [] (
int i) { options::cdt_port = i; }
1043 return to_v8_string(&isolate, str);
1048 auto Ctx = isolate.GetCurrentContext();
1050 auto bs = v8::ArrayBuffer::NewBackingStore(
1053 v8::BackingStore::EmptyDeleter,
1056 auto buffer = v8::ArrayBuffer::New(&isolate, std::move(bs));
1059 std::cout <<
"Wasm code size: " << binary_size << std::endl;
1061 args_t module_args { buffer };
1062 auto wasm = Ctx->Global()->Get(Ctx,
mkstr(isolate,
"WebAssembly")).ToLocalChecked().As<v8::Object>();
1063 auto wasm_module =
wasm->Get(Ctx,
mkstr(isolate,
"Module")).ToLocalChecked().As<v8::Object>()
1064 ->CallAsConstructor(Ctx, 1, module_args).ToLocalChecked().As<v8::WasmModuleObject>();
1068 std::cout <<
"Machine code size: " << wasm_module->GetCompiledModule().Serialize().size << std::endl;
1070 args_t instance_args { wasm_module, imports };
1071 return wasm->Get(Ctx,
mkstr(isolate,
"Instance")).ToLocalChecked().As<v8::Object>()
1072 ->CallAsConstructor(Ctx, 2, instance_args).ToLocalChecked().As<v8::WasmModuleObject>();
1078 auto Ctx = isolate.GetCurrentContext();
1079 auto env = v8::Object::New(&isolate);
1083 for (
auto &table : tables) {
1084 auto off = context.map_table(table.get());
1087 std::ostringstream oss;
1088 oss << table.get().name() <<
"_mem";
1089 M_DISCARD env->Set(Ctx, to_v8_string(&isolate, oss.str()), v8::Int32::New(&isolate, off));
1094 oss << table.get().name() <<
"_num_rows";
1095 M_DISCARD env->Set(Ctx, to_v8_string(&isolate, oss.str()), v8::Int32::New(&isolate, table.get().store().num_rows()));
1102 std::size_t bytes = 0;
1103 for (
auto literal : literals)
1104 bytes += strlen(literal) + 1;
1106 if (aligned_bytes) {
1107 auto base_addr = context.vm.as<uint8_t*>() + context.heap;
1108 M_DISCARD mmap(base_addr, aligned_bytes, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
1109 char *start_addr =
reinterpret_cast<char*
>(base_addr);
1110 char *dst = start_addr;
1111 for (
auto literal : literals) {
1113 dst = stpcpy(dst, literal) + 1;
1115 context.heap += aligned_bytes;
1116 context.install_guard_page();
1123#define EMIT_FUNC_IMPORTS(KEYTYPE, IDXNAME, SUFFIX) \
1124 Module::Get().emit_function_import<uint32_t(std::size_t,KEYTYPE)>(M_STR(idx_lower_bound_##IDXNAME##_##SUFFIX)); \
1125 Module::Get().emit_function_import<uint32_t(std::size_t,KEYTYPE)>(M_STR(idx_upper_bound_##IDXNAME##_##SUFFIX)); \
1126 Module::Get().emit_function_import<void(std::size_t,uint32_t,void*,uint32_t)>(M_STR(idx_scan_##IDXNAME##_##SUFFIX))
1142#undef EMIT_FUNC_IMPORTS
1144#define ADD_FUNC(FUNC, NAME) { \
1145 auto func = v8::Function::New(Ctx, (FUNC)).ToLocalChecked(); \
1146 env->Set(Ctx, mkstr(isolate, NAME), func).Check(); \
1148#define ADD_FUNC_(FUNC) ADD_FUNC(FUNC, #FUNC)
1155#define ADD_FUNCS(IDXTYPE, KEYTYPE, V8TYPE, IDXNAME, SUFFIX) \
1156 ADD_FUNC(index_seek<M_COMMA(IDXTYPE<KEYTYPE>) M_COMMA(V8TYPE) true>, M_STR(idx_lower_bound_##IDXNAME##_##SUFFIX)) \
1157 ADD_FUNC(index_seek<M_COMMA(IDXTYPE<KEYTYPE>) M_COMMA(V8TYPE) false>, M_STR(idx_upper_bound_##IDXNAME##_##SUFFIX)) \
1158 ADD_FUNC(index_sequential_scan<IDXTYPE<KEYTYPE>>, M_STR(idx_scan_##IDXNAME##_##SUFFIX))
1184 auto Ctx = isolate.GetCurrentContext();
1185 return v8::JSON::Stringify(Ctx, val).ToLocalChecked();
1191 std::ostringstream oss;
1195 auto json =
to_json(isolate, env);
1196 std::string env_str = *v8::String::Utf8Value(&isolate, json);
1197 if (env_str !=
"{}") env_str.insert(env_str.length() - 1,
",");
1198 env_str.insert(env_str.length() - 1,
"\"insist\": function (arg) { assert(arg); },");
1199 env_str.insert(env_str.length() - 1,
"\"print\": function (arg) { console.log(arg); },");
1200 env_str.insert(env_str.length() - 1,
"\"throw\": function (ex) { console.error(ex); },");
1201 env_str.insert(env_str.length() - 1,
"\"read_result_set\": read_result_set,");
1205let importObject = { \"imports\": " << env_str <<
" };\n\
1206const bytes = Uint8Array.from([";
1207 for (
auto p = binary_addr, end = p + binary_size; p != end; ++p) {
1208 if (p != binary_addr) oss <<
", ";
1209 oss << unsigned(*p);
1214WebAssembly.compile(bytes).then(\n\
1215 (module) => WebAssembly.instantiate(module, importObject),\n\
1216 (error) => console.error(`An error occurred during module compilation: ${error}`)\n\
1218 function(instance) {\n\
1219 set_wasm_instance_raw_memory(instance, " << wasm_context.
id <<
");\n\
1220 const num_tuples = instance.exports.main();\n\
1221 console.log('The result set contains %i tuples.', num_tuples);\n\
1224 (error) => console.error(`An error occurred during module instantiation: ${error}`)\n\
1229 const char *name =
"query.js";
1230 std::ofstream file(name, std::ios_base::out);
1233 std::cerr <<
"Creating debug JS script " << name << std::endl;
1244 return std::string(name);
1249 auto Ctx = isolate.GetCurrentContext();
1253 inspector.
start([&]() {
1257 std::ifstream js_in(filename);
1258 std::string js(std::istreambuf_iterator<char>(js_in), std::istreambuf_iterator<char>{});
1259 v8::Local<v8::String> js_src =
mkstr(isolate, js);
1260 std::string path = std::string(
"file://./") + filename;
1261 v8::ScriptOrigin js_origin = v8::ScriptOrigin(&isolate,
mkstr(isolate, path));
1262 auto script = v8::Script::Compile(Ctx, js_src, &js_origin);
1263 if (script.IsEmpty())
1264 throw std::runtime_error(
"failed to compile script");
1266 auto result = script.ToLocalChecked()->Run(Ctx);
1267 if (result.IsEmpty())
1268 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)
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.
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_[]