From b9e1675ebf8f4f4c7e309400c00abcd8a0b27add Mon Sep 17 00:00:00 2001 From: jeaye Date: Sat, 30 Nov 2024 13:20:27 -0800 Subject: [PATCH] Move over-max-arg packing to analysis --- .../include/cpp/jank/analyze/expr/list.hpp | 38 ++++++ .../include/cpp/jank/analyze/expr/vector.hpp | 6 +- .../include/cpp/jank/analyze/expression.hpp | 2 + compiler+runtime/include/cpp/jank/c_api.h | 13 ++ .../cpp/jank/codegen/llvm_processor.hpp | 2 + .../include/cpp/jank/evaluate.hpp | 1 + .../cpp/jank/runtime/obj/persistent_list.hpp | 4 +- .../include/cpp/jank/runtime/visit.hpp | 23 ++-- .../src/cpp/jank/analyze/processor.cpp | 43 ++++++- compiler+runtime/src/cpp/jank/c_api.cpp | 59 +++++++++ .../src/cpp/jank/codegen/llvm_processor.cpp | 33 +++++- compiler+runtime/src/cpp/jank/evaluate.cpp | 28 +++-- .../cpp/jank/runtime/behavior/callable.cpp | 112 +++++++++--------- .../cpp/jank/runtime/obj/persistent_list.cpp | 8 +- 14 files changed, 278 insertions(+), 94 deletions(-) create mode 100644 compiler+runtime/include/cpp/jank/analyze/expr/list.hpp diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/list.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/list.hpp new file mode 100644 index 00000000..f59e7eaf --- /dev/null +++ b/compiler+runtime/include/cpp/jank/analyze/expr/list.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include + +namespace jank::analyze::expr +{ + using namespace jank::runtime; + + template + struct list : expression_base + { + native_vector> data_exprs; + option meta; + obj::persistent_list_ptr data{}; + + void propagate_position(expression_position const pos) + { + position = pos; + } + + object_ptr to_runtime_data() const + { + object_ptr exprs(make_box()); + for(auto const &e : data_exprs) + { + exprs = conj(exprs, e->to_runtime_data()); + } + + return merge(static_cast(this)->to_runtime_data(), + obj::persistent_array_map::create_unique(make_box("__type"), + make_box("expr::list"), + make_box("data_exprs"), + exprs, + make_box("meta"), + jank::detail::to_runtime_data(meta))); + } + }; +} diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/vector.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/vector.hpp index d1c2c693..03e535b6 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/vector.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/vector.hpp @@ -20,17 +20,17 @@ namespace jank::analyze::expr object_ptr to_runtime_data() const { - object_ptr pair_maps(make_box()); + object_ptr exprs(make_box()); for(auto const &e : data_exprs) { - pair_maps = conj(pair_maps, e->to_runtime_data()); + exprs = conj(exprs, e->to_runtime_data()); } return merge(static_cast(this)->to_runtime_data(), obj::persistent_array_map::create_unique(make_box("__type"), make_box("expr::vector"), make_box("data_exprs"), - pair_maps, + exprs, make_box("meta"), jank::detail::to_runtime_data(meta))); } diff --git a/compiler+runtime/include/cpp/jank/analyze/expression.hpp b/compiler+runtime/include/cpp/jank/analyze/expression.hpp index e074dc2e..0dbeaa4b 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expression.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expression.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ namespace jank::analyze expr::var_ref, expr::call, expr::primitive_literal, + expr::list, expr::vector, expr::map, expr::set, diff --git a/compiler+runtime/include/cpp/jank/c_api.h b/compiler+runtime/include/cpp/jank/c_api.h index 41a2e823..e582e448 100644 --- a/compiler+runtime/include/cpp/jank/c_api.h +++ b/compiler+runtime/include/cpp/jank/c_api.h @@ -92,6 +92,18 @@ extern "C" jank_object_ptr a8, jank_object_ptr a9, jank_object_ptr a10); + jank_object_ptr jank_call11(jank_object_ptr f, + jank_object_ptr a1, + jank_object_ptr a2, + jank_object_ptr a3, + jank_object_ptr a4, + jank_object_ptr a5, + jank_object_ptr a6, + jank_object_ptr a7, + jank_object_ptr a8, + jank_object_ptr a9, + jank_object_ptr a10, + jank_object_ptr rest); jank_object_ptr jank_nil(); jank_object_ptr jank_true(); @@ -102,6 +114,7 @@ extern "C" jank_object_ptr jank_symbol_create(jank_object_ptr ns, jank_object_ptr name); jank_object_ptr jank_character_create(char const *s); + jank_object_ptr jank_list_create(uint64_t size, ...); jank_object_ptr jank_vector_create(uint64_t size, ...); jank_object_ptr jank_map_create(uint64_t pairs, ...); jank_object_ptr jank_set_create(uint64_t size, ...); diff --git a/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp b/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp index 0e0c443a..6d015ee7 100644 --- a/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp +++ b/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp @@ -80,6 +80,8 @@ namespace jank::codegen analyze::expr::function_arity const &); llvm::Value *gen(analyze::expr::primitive_literal const &, analyze::expr::function_arity const &); + llvm::Value *gen(analyze::expr::list const &, + analyze::expr::function_arity const &); llvm::Value *gen(analyze::expr::vector const &, analyze::expr::function_arity const &); llvm::Value *gen(analyze::expr::map const &, diff --git a/compiler+runtime/include/cpp/jank/evaluate.hpp b/compiler+runtime/include/cpp/jank/evaluate.hpp index a978d263..714a4f57 100644 --- a/compiler+runtime/include/cpp/jank/evaluate.hpp +++ b/compiler+runtime/include/cpp/jank/evaluate.hpp @@ -14,6 +14,7 @@ namespace jank::evaluate runtime::object_ptr eval(analyze::expr::var_ref const &); runtime::object_ptr eval(analyze::expr::call const &); runtime::object_ptr eval(analyze::expr::primitive_literal const &); + runtime::object_ptr eval(analyze::expr::list const &); runtime::object_ptr eval(analyze::expr::vector const &); runtime::object_ptr eval(analyze::expr::map const &); runtime::object_ptr eval(analyze::expr::set const &); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_list.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_list.hpp index fa55592c..b148a5ff 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/persistent_list.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/persistent_list.hpp @@ -21,10 +21,10 @@ namespace jank::runtime static native_box create(native_box s); static_object() = default; - static_object(static_object &&) = default; + static_object(static_object &&) noexcept = default; static_object(static_object const &) = default; - static_object(value_type &&d); static_object(value_type const &d); + static_object(object_ptr meta, value_type const &d); /* TODO: This is broken when `args` is a value_type list we're looking to wrap in another list. * It just uses the copy ctor. */ diff --git a/compiler+runtime/include/cpp/jank/runtime/visit.hpp b/compiler+runtime/include/cpp/jank/runtime/visit.hpp index cabdedcb..f0b939a1 100644 --- a/compiler+runtime/include/cpp/jank/runtime/visit.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/visit.hpp @@ -341,18 +341,9 @@ namespace jank::runtime break; default: { - /* TODO: Use fmt when possible. */ - throw std::runtime_error{ "invalid object type: " - + std::to_string(static_cast(const_erased->type)) }; - //throw std::runtime_error - //{ - // fmt::format - // ( - // "invalid object type: {} raw value {}", - // magic_enum::enum_name(erased->type), - // static_cast(erased->type) - // ) - //}; + throw std::runtime_error{ fmt::format("invalid object type: {} raw value {}", + magic_enum::enum_name(erased->type), + static_cast(erased->type)) }; } break; } @@ -537,7 +528,7 @@ namespace jank::runtime return visit_seqable( fn, [=]() -> decltype(fn(obj::cons_ptr{}, std::forward(args)...)) { - throw std::runtime_error{ "not seqable: " + to_string(const_erased) }; + throw std::runtime_error{ "not seqable: " + to_code_string(const_erased) }; }, const_erased, std::forward(args)...); @@ -586,7 +577,7 @@ namespace jank::runtime return visit_map_like( fn, [=]() -> decltype(fn(obj::persistent_hash_map_ptr{}, std::forward(args)...)) { - throw std::runtime_error{ "not map-like: " + to_string(const_erased) }; + throw std::runtime_error{ "not map-like: " + to_code_string(const_erased) }; }, const_erased, std::forward(args)...); @@ -630,7 +621,7 @@ namespace jank::runtime return visit_set_like( fn, [=]() -> decltype(fn(obj::persistent_hash_set_ptr{}, std::forward(args)...)) { - throw std::runtime_error{ "not set-like: " + to_string(const_erased) }; + throw std::runtime_error{ "not set-like: " + to_code_string(const_erased) }; }, const_erased, std::forward(args)...); @@ -675,7 +666,7 @@ namespace jank::runtime return visit_number_like( fn, [=]() -> decltype(fn(obj::integer_ptr{}, std::forward(args)...)) { - throw std::runtime_error{ "not a number: " + to_string(const_erased) }; + throw std::runtime_error{ "not a number: " + to_code_string(const_erased) }; }, const_erased, std::forward(args)...); diff --git a/compiler+runtime/src/cpp/jank/analyze/processor.cpp b/compiler+runtime/src/cpp/jank/analyze/processor.cpp index 90cea451..49618827 100644 --- a/compiler+runtime/src/cpp/jank/analyze/processor.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/processor.cpp @@ -1387,10 +1387,16 @@ namespace jank::analyze } native_vector arg_exprs; - arg_exprs.reserve(arg_count); - for(auto const &s : o->data.rest()) + arg_exprs.reserve(std::min(arg_count, runtime::max_params + 1)); + + auto it(o->data.rest()); + for(size_t i{}; i < runtime::max_params && i < arg_count; ++i, it = it.rest()) { - auto arg_expr(analyze(s, current_frame, expression_position::value, fn_ctx, needs_arg_box)); + auto arg_expr(analyze(it.first().unwrap(), + current_frame, + expression_position::value, + fn_ctx, + needs_arg_box)); if(arg_expr.is_err()) { return arg_expr; @@ -1398,6 +1404,37 @@ namespace jank::analyze arg_exprs.emplace_back(arg_expr.expect_ok()); } + /* If we have more args than a fn allows, we need to pack all of the extras + * into a single list and tack that on at the end. So, if max_params is 10, and + * we pass 15 args, we'll pass 10 normally and then we'll have a special 11th + * arg which is a list containing the 5 remaining params. We rely on dynamic_call + * to do the hard work of packing that in the shape the function actually wants, + * based on its highest fixed arity flag. */ + if(runtime::max_params < arg_count) + { + native_vector packed_arg_exprs; + for(size_t i{ runtime::max_params }; i < arg_count; ++i, it = it.rest()) + { + auto arg_expr(analyze(it.first().unwrap(), + current_frame, + expression_position::value, + fn_ctx, + needs_arg_box)); + if(arg_expr.is_err()) + { + return arg_expr; + } + packed_arg_exprs.emplace_back(arg_expr.expect_ok()); + } + expr::list list{ + expression_base{ {}, expression_position::value, current_frame, needs_arg_box }, + std::move(packed_arg_exprs), + none, + nullptr + }; + arg_exprs.emplace_back(make_box(std::move(list))); + } + auto const recursion_ref(boost::get>(&source->data)); if(recursion_ref) { diff --git a/compiler+runtime/src/cpp/jank/c_api.cpp b/compiler+runtime/src/cpp/jank/c_api.cpp index da9a59b9..cfbd0d4c 100644 --- a/compiler+runtime/src/cpp/jank/c_api.cpp +++ b/compiler+runtime/src/cpp/jank/c_api.cpp @@ -294,6 +294,45 @@ extern "C" a10_obj); } + jank_object_ptr jank_call11(jank_object_ptr const f, + jank_object_ptr const a1, + jank_object_ptr const a2, + jank_object_ptr const a3, + jank_object_ptr const a4, + jank_object_ptr const a5, + jank_object_ptr const a6, + jank_object_ptr const a7, + jank_object_ptr const a8, + jank_object_ptr const a9, + jank_object_ptr const a10, + jank_object_ptr const rest) + { + auto const f_obj(reinterpret_cast(f)); + auto const a1_obj(reinterpret_cast(a1)); + auto const a2_obj(reinterpret_cast(a2)); + auto const a3_obj(reinterpret_cast(a3)); + auto const a4_obj(reinterpret_cast(a4)); + auto const a5_obj(reinterpret_cast(a5)); + auto const a6_obj(reinterpret_cast(a6)); + auto const a7_obj(reinterpret_cast(a7)); + auto const a8_obj(reinterpret_cast(a8)); + auto const a9_obj(reinterpret_cast(a9)); + auto const a10_obj(reinterpret_cast(a10)); + auto const rest_obj(reinterpret_cast(rest)); + return dynamic_call(f_obj, + a1_obj, + a2_obj, + a3_obj, + a4_obj, + a5_obj, + a6_obj, + a7_obj, + a8_obj, + a9_obj, + a10_obj, + try_object(rest_obj)); + } + jank_object_ptr jank_nil() { return erase(obj::nil::nil_const()); @@ -338,6 +377,26 @@ extern "C" return erase(make_box(read::parse::get_char_from_literal(s).unwrap())); } + jank_object_ptr jank_list_create(uint64_t const size, ...) + { + /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) */ + va_list args; + va_start(args, size); + + native_vector v; + + for(uint64_t i{}; i < size; ++i) + { + /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) */ + v.emplace_back(reinterpret_cast(va_arg(args, jank_object_ptr))); + } + + va_end(args); + + runtime::detail::native_persistent_list const npl{ v.rbegin(), v.rend() }; + return erase(make_box(std::move(npl))); + } + jank_object_ptr jank_vector_create(uint64_t const size, ...) { /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) */ diff --git a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp index 242c6478..b67bcdfa 100644 --- a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp +++ b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp @@ -301,12 +301,14 @@ namespace jank::codegen static native_persistent_string arity_to_call_fn(size_t const arity) { + /* Anything max_params + 1 or higher gets packed into a list so we + * just end up calling max_params + 1 at most. */ switch(arity) { - case 0 ... 10: + case 0 ... runtime::max_params: return fmt::format("jank_call{}", arity); default: - throw std::runtime_error{ fmt::format("invalid fn arity: {}", arity) }; + return fmt::format("jank_call{}", runtime::max_params + 1); } } @@ -386,6 +388,33 @@ namespace jank::codegen return ret; } + llvm::Value *llvm_processor::gen(analyze::expr::list const &expr, + analyze::expr::function_arity const &arity) + { + auto const fn_type( + llvm::FunctionType::get(ctx->builder->getPtrTy(), { ctx->builder->getInt64Ty() }, true)); + auto const fn(ctx->module->getOrInsertFunction("jank_list_create", fn_type)); + + auto const size(expr.data_exprs.size()); + std::vector args; + args.reserve(1 + size); + args.emplace_back(ctx->builder->getInt64(size)); + + for(auto const &expr : expr.data_exprs) + { + args.emplace_back(gen(expr, arity)); + } + + auto const call(ctx->builder->CreateCall(fn, args)); + + if(expr.position == analyze::expression_position::tail) + { + return ctx->builder->CreateRet(call); + } + + return call; + } + llvm::Value *llvm_processor::gen(analyze::expr::vector const &expr, analyze::expr::function_arity const &arity) { diff --git a/compiler+runtime/src/cpp/jank/evaluate.cpp b/compiler+runtime/src/cpp/jank/evaluate.cpp index df12c9fe..b4794d28 100644 --- a/compiler+runtime/src/cpp/jank/evaluate.cpp +++ b/compiler+runtime/src/cpp/jank/evaluate.cpp @@ -163,7 +163,6 @@ namespace jank::evaluate arg_vals.emplace_back(eval(arg_expr)); } - /* TODO: Use apply_to */ switch(arg_vals.size()) { case 0: @@ -235,12 +234,6 @@ namespace jank::evaluate arg_vals[9]); default: { - /* TODO: This could be optimized; making lists sucks right now. */ - runtime::detail::native_persistent_list all{ arg_vals.rbegin(), arg_vals.rend() }; - for(size_t i{}; i < 10; ++i) - { - all = all.rest(); - } return dynamic_call(source, arg_vals[0], arg_vals[1], @@ -252,7 +245,7 @@ namespace jank::evaluate arg_vals[7], arg_vals[8], arg_vals[9], - make_box(all)); + try_object(arg_vals[10])); } } } @@ -305,6 +298,25 @@ namespace jank::evaluate return expr.data; } + object_ptr eval(expr::list const &expr) + { + native_vector ret; + for(auto const &e : expr.data_exprs) + { + ret.emplace_back(eval(e)); + } + + runtime::detail::native_persistent_list const npl{ ret.rbegin(), ret.rend() }; + if(expr.meta.is_some()) + { + return make_box(expr.meta.unwrap(), std::move(npl)); + } + else + { + return make_box(std::move(npl)); + } + } + object_ptr eval(expr::vector const &expr) { runtime::detail::native_transient_vector ret; diff --git a/compiler+runtime/src/cpp/jank/runtime/behavior/callable.cpp b/compiler+runtime/src/cpp/jank/runtime/behavior/callable.cpp index 73e09f43..346005d4 100644 --- a/compiler+runtime/src/cpp/jank/runtime/behavior/callable.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/behavior/callable.cpp @@ -708,6 +708,7 @@ namespace jank::runtime object_ptr const a10, obj::persistent_list_ptr const rest) { + /* TODO: Move call fns into var so we can remove these checks. */ if(source->type == object_type::var) { source = runtime::deref(source); @@ -876,93 +877,90 @@ namespace jank::runtime case 1: return dynamic_call(source, s->first()); case 2: - return dynamic_call(source, s->first(), runtime::next_in_place(s)->first()); + return dynamic_call(source, s->first(), s->next_in_place()->first()); case 3: return dynamic_call(source, s->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first()); + s->next_in_place()->first(), + s->next_in_place()->first()); case 4: return dynamic_call(source, s->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first()); + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first()); case 5: return dynamic_call(source, s->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first()); + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first()); case 6: return dynamic_call(source, s->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first()); + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first()); case 7: return dynamic_call(source, s->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first()); + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first()); case 8: return dynamic_call(source, s->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first()); + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first()); case 9: return dynamic_call(source, s->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first()); + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first()); case 10: return dynamic_call(source, s->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first()); + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first()); default: return dynamic_call(source, s->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), - runtime::next_in_place(s)->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), + s->next_in_place()->first(), obj::persistent_list::create(next_in_place(s))); } }, - [&]() -> object_ptr { - throw std::runtime_error{ fmt::format("not seqable: {}", runtime::to_string(args)) }; - }, args); } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_list.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_list.cpp index 6b7d86ec..2518b445 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_list.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_list.cpp @@ -4,13 +4,15 @@ namespace jank::runtime { - obj::persistent_list::static_object(runtime::detail::native_persistent_list &&d) - : data{ std::move(d) } + obj::persistent_list::static_object(runtime::detail::native_persistent_list const &d) + : data{ d } { } - obj::persistent_list::static_object(runtime::detail::native_persistent_list const &d) + obj::persistent_list::static_object(object_ptr const meta, + runtime::detail::native_persistent_list const &d) : data{ d } + , meta{ meta } { }