xo-interpreter: Object->TaggedPtr conversion (prep for primitives)
This commit is contained in:
parent
22670cda3d
commit
4488117ac3
16 changed files with 371 additions and 26 deletions
40
xo-alloc/include/xo/alloc/Blob.hpp
Normal file
40
xo-alloc/include/xo/alloc/Blob.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/** @file Blob.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Object.hpp"
|
||||
#include "IAlloc.hpp"
|
||||
|
||||
namespace xo {
|
||||
/** Use to allocate opaque binary data,
|
||||
* with object header.
|
||||
*
|
||||
* Not sure if we want to bother implementing reflection for this...
|
||||
**/
|
||||
class Blob : public Object {
|
||||
public:
|
||||
Blob(std::size_t z) : z_{z} {};
|
||||
|
||||
static gp<Blob> make(gc::IAlloc * mm, std::size_t z);
|
||||
|
||||
std::size_t size() const { return z_; }
|
||||
std::byte * data() { return data_; }
|
||||
|
||||
virtual TaggedPtr self_tp() const final override;
|
||||
virtual void display(std::ostream & os) const final override;
|
||||
|
||||
virtual std::size_t _shallow_size() const final override;
|
||||
virtual Object * _shallow_copy(gc::IAlloc * gc) const final override;
|
||||
virtual std::size_t _forward_children(gc::IAlloc * gc) final override;
|
||||
|
||||
private:
|
||||
std::size_t z_ = 0;
|
||||
/** flexible array, with @ref z_ bytes **/
|
||||
std::byte data_[];
|
||||
};
|
||||
}
|
||||
|
||||
/* end Blob.hpp */
|
||||
57
xo-alloc/src/alloc/Blob.cpp
Normal file
57
xo-alloc/src/alloc/Blob.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/** @file Blob.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#include "Blob.hpp"
|
||||
#include "xo/reflect/Reflect.hpp"
|
||||
#include "xo/alloc/IAlloc.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::reflect::Reflect;
|
||||
using xo::reflect::TaggedPtr;
|
||||
|
||||
gp<Blob>
|
||||
Blob::make(gc::IAlloc * mm, std::size_t z) {
|
||||
std::byte * mem = mm->alloc(sizeof(Blob) + z);
|
||||
|
||||
return new (mem) Blob(z);
|
||||
}
|
||||
|
||||
TaggedPtr
|
||||
Blob::self_tp() const
|
||||
{
|
||||
return Reflect::make_tp(const_cast<Blob*>(this));
|
||||
}
|
||||
|
||||
void
|
||||
Blob::display(std::ostream & os) const
|
||||
{
|
||||
os << "<blob" << xtag("z", z_) << ">";
|
||||
}
|
||||
|
||||
std::size_t
|
||||
Blob::_shallow_size() const {
|
||||
return sizeof(Blob) + z_;
|
||||
}
|
||||
|
||||
Object *
|
||||
Blob::_shallow_copy(gc::IAlloc * mm) const {
|
||||
Cpof cpof(mm, this);
|
||||
std::byte * cp_mem = mm->alloc_gc_copy(sizeof(Blob) + z_, this);
|
||||
|
||||
gp<Blob> copy = new (cp_mem) Blob(z_);
|
||||
|
||||
::memcpy(copy->data(), data_, z_);
|
||||
|
||||
return copy.get();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
Blob::_forward_children(gc::IAlloc *)
|
||||
{
|
||||
return this->_shallow_size();
|
||||
}
|
||||
}
|
||||
|
||||
/* end Blob.cpp */
|
||||
|
|
@ -9,6 +9,7 @@ set(SELF_SRCS
|
|||
GcStatistics.cpp
|
||||
ObjectStatistics.cpp
|
||||
Object.cpp
|
||||
Blob.cpp
|
||||
Forwarding1.cpp
|
||||
generation.cpp
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/** @file FunctionInterface.hpp
|
||||
/** @file ProcedureExprInterface.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
|
@ -10,14 +10,14 @@
|
|||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
class FunctionExprInterface : public Expression {
|
||||
class ProcedureExprInterface : public Expression {
|
||||
public:
|
||||
FunctionExprInterface(exprtype extype, TypeDescr fn_type)
|
||||
ProcedureExprInterface(exprtype extype, TypeDescr fn_type)
|
||||
: Expression(extype, fn_type) {}
|
||||
|
||||
/** downcast from Expression **/
|
||||
static bp<FunctionExprInterface> from(bp<Expression> x) {
|
||||
return bp<FunctionExprInterface>::from(x);
|
||||
static bp<ProcedureExprInterface> from(bp<Expression> x) {
|
||||
return bp<ProcedureExprInterface>::from(x);
|
||||
}
|
||||
|
||||
virtual const std::string & name() const = 0;
|
||||
|
|
@ -30,4 +30,4 @@ namespace xo {
|
|||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end FunctionInterface.hpp **/
|
||||
/** end ProcedureExprInterface.hpp **/
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Expression.hpp"
|
||||
#include "FunctionExprInterface.hpp"
|
||||
#include "ProcedureExprInterface.hpp"
|
||||
#include "Variable.hpp"
|
||||
#include "LocalSymtab.hpp"
|
||||
#include <map>
|
||||
|
|
@ -19,7 +19,7 @@ namespace xo {
|
|||
* @brief abstract syntax tree for a function definition
|
||||
*
|
||||
**/
|
||||
class Lambda : public FunctionExprInterface {
|
||||
class Lambda : public ProcedureExprInterface {
|
||||
public:
|
||||
/**
|
||||
* @p name. Name for this lambda -- must be unique
|
||||
|
|
|
|||
|
|
@ -5,19 +5,19 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "FunctionExprInterface.hpp"
|
||||
#include "ProcedureExprInterface.hpp"
|
||||
#include "llvmintrinsic.hpp"
|
||||
#include <type_traits>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
class PrimitiveExprInterface : public FunctionExprInterface {
|
||||
class PrimitiveExprInterface : public ProcedureExprInterface {
|
||||
public:
|
||||
using void_function_type = void (*)();
|
||||
|
||||
public:
|
||||
explicit PrimitiveExprInterface(TypeDescr fn_type)
|
||||
: FunctionExprInterface(exprtype::primitive, fn_type) {}
|
||||
: ProcedureExprInterface(exprtype::primitive, fn_type) {}
|
||||
|
||||
/** downcast from Expression **/
|
||||
static bp<PrimitiveExprInterface> from(bp<Expression> x) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/** @file FunctionExprInterface.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Expression.hpp"
|
||||
//#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
class ProcedureExprInterface : public Expression {
|
||||
public:
|
||||
ProcedureExprInterface(exprtype extype, TypeDescr fn_type)
|
||||
: Expression(extype, fn_type) {}
|
||||
|
||||
/** downcast from Expression **/
|
||||
static bp<ProcedureExprInterface> from(bp<Expression> x) {
|
||||
return bp<ProcedureExprInterface>::from(x);
|
||||
}
|
||||
|
||||
virtual const std::string & name() const = 0;
|
||||
virtual int n_arg() const = 0; // { return this->value_td()->n_fn_arg(); }
|
||||
virtual TypeDescr fn_retval() const = 0; // { return this->value_td()->fn_retval(); }
|
||||
virtual TypeDescr fn_arg(uint32_t i) const = 0; // { return this->value_td()->fn_arg(i); }
|
||||
|
||||
private:
|
||||
}; /*FunctionInterface*/
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end FunctionExprInterface.hpp **/
|
||||
|
|
@ -259,7 +259,7 @@ namespace xo {
|
|||
TypeDescr lambda_td,
|
||||
const rp<LocalSymtab> & local_env,
|
||||
const rp<Expression> & body)
|
||||
: FunctionExprInterface(exprtype::lambda, lambda_td),
|
||||
: ProcedureExprInterface(exprtype::lambda, lambda_td),
|
||||
name_{name},
|
||||
body_{body},
|
||||
local_env_{local_env}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace xo {
|
|||
**/
|
||||
struct type2llvm {
|
||||
public:
|
||||
using FunctionInterface = xo::scm::FunctionExprInterface;
|
||||
using FunctionInterface = xo::scm::ProcedureExprInterface;
|
||||
using Lambda = xo::scm::Lambda;
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* @file List.hpp
|
||||
/** @file List.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2025
|
||||
*/
|
||||
* @author: Roland Conybeare, Aug 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
@ -70,3 +70,5 @@ namespace xo {
|
|||
};
|
||||
}
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end List.hpp */
|
||||
|
|
|
|||
|
|
@ -18,10 +18,11 @@ namespace xo {
|
|||
struct Converter {
|
||||
using TaggedPtr = xo::reflect::TaggedPtr;
|
||||
using ConvertToObjectFn = gp<Object> (*)(gc::IAlloc *, const TaggedPtr &);
|
||||
using ConvertFromObjectFn = TaggedPtr (*)(gc::IAlloc *, gp<Object> obj);
|
||||
|
||||
public:
|
||||
Converter() = default;
|
||||
explicit Converter(ConvertToObjectFn f) : cvt_to_object_{f} {}
|
||||
explicit Converter(ConvertToObjectFn to, ConvertFromObjectFn from) : cvt_to_object_{to}, cvt_from_object_{from} {}
|
||||
|
||||
/** convert tagged pointer @p tp to new object,
|
||||
* allocated via @p mm.
|
||||
|
|
@ -30,6 +31,14 @@ namespace xo {
|
|||
* see @ref ObjectConverter
|
||||
**/
|
||||
ConvertToObjectFn cvt_to_object_ = nullptr;
|
||||
|
||||
/** convert object to tagged pointer @p,
|
||||
* allocated via @p mm.
|
||||
*
|
||||
* Conversion will typically be for some specific type;
|
||||
* see @ref ObjectConverter
|
||||
**/
|
||||
ConvertFromObjectFn cvt_from_object_ = nullptr;
|
||||
};
|
||||
|
||||
/** @class ObjectConverter
|
||||
|
|
@ -53,6 +62,7 @@ namespace xo {
|
|||
class ObjectConverter {
|
||||
public:
|
||||
using TaggedPtr = xo::reflect::TaggedPtr;
|
||||
using TypeId = xo::reflect::TypeId;
|
||||
using IAlloc = xo::gc::IAlloc;
|
||||
|
||||
/** sets up standard conversions **/
|
||||
|
|
@ -60,7 +70,7 @@ namespace xo {
|
|||
|
||||
/** establish conversion: use @p fn to convert values of type @tparam T. **/
|
||||
template <typename T>
|
||||
void establish_conversion(Converter::ConvertToObjectFn fn);
|
||||
void establish_conversion(Converter::ConvertToObjectFn to, Converter::ConvertFromObjectFn from);
|
||||
|
||||
/** convert tagged poitner @p tp to object. allocates memory only from @p mm.
|
||||
* return nullptr if no converter available and @p throw_flag not set.
|
||||
|
|
@ -76,6 +86,13 @@ namespace xo {
|
|||
template <typename T>
|
||||
gp<Object> to_object(IAlloc * mm, const T & x, bool throw_flag);
|
||||
|
||||
/** convert object @p obj to tagged pointer, with typeid @target_id.
|
||||
* Allocates memory only from @p mm.
|
||||
* return null TaggedPtr if no converter available and @p throw_flag not set.
|
||||
* Throw exception if no converter available and @p throw_flag set.
|
||||
**/
|
||||
TaggedPtr tp_from_object(IAlloc * mm, gp<Object> & obj, TypeId target_id, bool throw_flag);
|
||||
|
||||
private:
|
||||
/** expandable type-driven conversion table.
|
||||
**/
|
||||
|
|
@ -84,7 +101,8 @@ namespace xo {
|
|||
|
||||
template <typename T>
|
||||
void
|
||||
ObjectConverter::establish_conversion(Converter::ConvertToObjectFn fn)
|
||||
ObjectConverter::establish_conversion(Converter::ConvertToObjectFn to,
|
||||
Converter::ConvertFromObjectFn from)
|
||||
{
|
||||
using xo::reflect::TypeDescrW;
|
||||
using xo::reflect::Reflect;
|
||||
|
|
@ -92,7 +110,7 @@ namespace xo {
|
|||
TypeDescrW td = Reflect::require<T>();
|
||||
Converter * cvt = cvt_.require(td);
|
||||
|
||||
*cvt = Converter(fn);
|
||||
*cvt = Converter(to, from);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
|||
70
xo-object/include/xo/object/Primitive.hpp
Normal file
70
xo-object/include/xo/object/Primitive.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/** @file Primitive.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Procedure.hpp"
|
||||
#include "CVector.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace obj {
|
||||
// TODO: consider PrimitiveInterface here
|
||||
|
||||
/** @class Primitive
|
||||
* @brief Procedure implemented natively, i.e. in c++
|
||||
*
|
||||
* @tparam FunctionType can be:
|
||||
* - a C-style function signature such as double(*)(double)
|
||||
* - a std::function, such as std::function<double(double)>
|
||||
**/
|
||||
template <typename Fn>
|
||||
class PrimitiveBase : public Procedure {
|
||||
public:
|
||||
using function_type = Fn;
|
||||
|
||||
public:
|
||||
explicit PrimitiveBase(Converter & cvt, Fn impl) : converter_{cvt}, impl_{std::move(impl)} {}
|
||||
|
||||
// inherited from Procedure..
|
||||
|
||||
virtual std::size_t n_args() const override = 0;
|
||||
virtual gp<Object> apply_nocheck(const CVector<gp<Object>> & args) override = 0;
|
||||
|
||||
protected:
|
||||
Converter & converter_;
|
||||
Fn impl_;
|
||||
};
|
||||
|
||||
template <typename Fn>
|
||||
class Primitive : public PrimitiveBase<Fn> {
|
||||
};
|
||||
|
||||
template <Ret, Arg1, Arg2>
|
||||
class Primitive<Ret (*)(Arg1, Arg2)> : public PrimitiveBase<Ret (*)(Arg1, Arg2)> {
|
||||
public:
|
||||
using Super = PrimitiveBase<Ret (*)(Arg1, Arg2)>;
|
||||
using function_type = Ret (*)(Arg1, Arg2);
|
||||
|
||||
public:
|
||||
explicit Primitive(Converter & cvt, function_type fn) : PrimitiveBase<Ret (*)(Arg1, Arg2)>{cvt, fn} {}
|
||||
|
||||
// inherited from Procedure..
|
||||
|
||||
virtual std::size_t n_args() const final override { return 2; }
|
||||
virtual gp<Object> apply_nocheck(const CVector<gp<Object>> & args) final override {
|
||||
/* note: args[0] will be this procedure. actual i'th function argument in args[i+1]
|
||||
*/
|
||||
|
||||
args[1]
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* end Primitive.hpp */
|
||||
31
xo-object/include/xo/object/Procedure.hpp
Normal file
31
xo-object/include/xo/object/Procedure.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/** @file Procedure.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Object.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace obj {
|
||||
/** @class ProcedureInterface
|
||||
* @brief Interface to a dynamically-typed procedure
|
||||
**/
|
||||
class Procedure : public Object {
|
||||
public:
|
||||
virtual std::size_t n_args() const = 0;
|
||||
virtual gp<Object> apply_nocheck(const CVector<gp<Object>> & args) = 0;
|
||||
|
||||
// inherited from Object..
|
||||
|
||||
// virtual TaggedPtr self_tp() const override;
|
||||
// virtual void display(std::ostream &) const override;
|
||||
// virtual size_t _shallow_size() const override;
|
||||
// virtual Object * _shallow_copy(gc::IAlloc *) const override;
|
||||
// virtual size_t _forward_children(gc::IAlloc *) override;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* end Procedure.hpp */
|
||||
|
|
@ -7,9 +7,13 @@
|
|||
#include "Integer.hpp"
|
||||
#include "Float.hpp"
|
||||
#include "Boolean.hpp"
|
||||
#include "TaggedPtr.hpp"
|
||||
#include "xo/alloc/Blob.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::reflect::Reflect;
|
||||
using xo::reflect::TaggedPtr;
|
||||
using xo::reflect::TypeId;
|
||||
using xo::gc::IAlloc;
|
||||
|
||||
namespace obj {
|
||||
|
|
@ -25,6 +29,34 @@ namespace xo {
|
|||
return Integer::make(mm, *native);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TaggedPtr
|
||||
object_to_int(IAlloc * mm, gp<Object> obj)
|
||||
{
|
||||
/* mm cannot be GC allocator!
|
||||
* That's Object-only
|
||||
*/
|
||||
|
||||
gp<Integer> int_obj = Integer::from(obj);
|
||||
|
||||
if (!int_obj.get()) {
|
||||
throw std::runtime_error(tostr("Object obj found where Integer expected",
|
||||
xtag("obj", obj)));
|
||||
}
|
||||
|
||||
/* allocate a Blob wrapper to satsify GC memory layout demands */
|
||||
|
||||
gp<Blob> tmp = Blob::make(mm, sizeof(T));
|
||||
|
||||
T * p = reinterpret_cast<T *>(tmp->data());
|
||||
|
||||
*p = int_obj->value();
|
||||
|
||||
/* WARNING: retval invalidated when *mm cleared/recycled/collected */
|
||||
|
||||
return Reflect::make_tp(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gp<Object>
|
||||
float_to_object(IAlloc * mm, const TaggedPtr & src)
|
||||
|
|
@ -36,6 +68,34 @@ namespace xo {
|
|||
return Float::make(mm, *native);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TaggedPtr
|
||||
object_to_float(IAlloc * mm, gp<Object> obj)
|
||||
{
|
||||
/* mm cannot be GC allocator!
|
||||
* That's Object-only
|
||||
*/
|
||||
|
||||
gp<Float> float_obj = Float::from(obj);
|
||||
|
||||
if (!float_obj.get()) {
|
||||
throw std::runtime_error(tostr("Object obj found where Float expected",
|
||||
xtag("obj", obj)));
|
||||
}
|
||||
|
||||
/* allocate a Blob wrapper to satsify GC memory layout demands */
|
||||
|
||||
gp<Blob> tmp = Blob::make(mm, sizeof(T));
|
||||
|
||||
T * p = reinterpret_cast<T *>(tmp->data());
|
||||
|
||||
*p = float_obj->value();
|
||||
|
||||
/* WARNING: retval invalidated when *mm cleared/recycled/collected */
|
||||
|
||||
return Reflect::make_tp(p);
|
||||
}
|
||||
|
||||
gp<Object>
|
||||
bool_to_object(IAlloc * /*mm*/, const TaggedPtr & src)
|
||||
{
|
||||
|
|
@ -45,16 +105,32 @@ namespace xo {
|
|||
|
||||
return Boolean::boolean_obj(*native);
|
||||
}
|
||||
|
||||
TaggedPtr
|
||||
object_to_bool(IAlloc * /*mm*/, gp<Object> obj)
|
||||
{
|
||||
static bool s_true = true;
|
||||
static bool s_false = false;
|
||||
|
||||
gp<Boolean> bool_obj = Boolean::from(obj);
|
||||
|
||||
if (!bool_obj.get()) {
|
||||
throw std::runtime_error(tostr("Object obj found where Boolean expected",
|
||||
xtag("obj", obj)));
|
||||
}
|
||||
|
||||
return Reflect::make_tp(bool_obj->value() ? &s_true : &s_false);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectConverter::ObjectConverter()
|
||||
{
|
||||
this->establish_conversion<std::int32_t>(&int_to_object<std::int32_t>);
|
||||
this->establish_conversion<std::int64_t>(&int_to_object<std::int64_t>);
|
||||
this->establish_conversion<std::int32_t>(&int_to_object<std::int32_t>, &object_to_int<std::int32_t>);
|
||||
this->establish_conversion<std::int64_t>(&int_to_object<std::int64_t>, &object_to_int<std::int64_t>);
|
||||
|
||||
this->establish_conversion<double>(&float_to_object<double>);
|
||||
this->establish_conversion<double>(&float_to_object<double>, &object_to_float<double>);
|
||||
|
||||
this->establish_conversion<bool>(&bool_to_object);
|
||||
this->establish_conversion<bool>(&bool_to_object, &object_to_bool);
|
||||
}
|
||||
|
||||
gp<Object>
|
||||
|
|
@ -69,7 +145,7 @@ namespace xo {
|
|||
return (cvt->cvt_to_object_)(mm, x_tp);
|
||||
} else {
|
||||
if (throw_flag) {
|
||||
throw std::runtime_error(tostr("no object-converter available for instance of type",
|
||||
throw std::runtime_error(tostr("no to-object-converter available for instance of type",
|
||||
xtag("id", x_tp.td()->id()),
|
||||
xtag("name", x_tp.td()->short_name())));
|
||||
}
|
||||
|
|
@ -77,6 +153,23 @@ namespace xo {
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TaggedPtr
|
||||
ObjectConverter::tp_from_object(IAlloc * mm, gp<Object> & obj, TypeId target_id, bool throw_flag)
|
||||
{
|
||||
const Converter * cvt = cvt_.lookup(target_id);
|
||||
|
||||
if (cvt) {
|
||||
return (cvt->cvt_from_object_)(mm, obj);
|
||||
} else {
|
||||
if (throw_flag) {
|
||||
throw std::runtime_error(tostr("no from-object-converter available for instance of type",
|
||||
xtag("id", target_id)));
|
||||
}
|
||||
|
||||
return TaggedPtr::universal_null();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ namespace xo {
|
|||
if (owner_ == owner::unique) {
|
||||
std::byte * mem = reinterpret_cast<std::byte *>(chars_);
|
||||
|
||||
copy->chars_ = reinterpret_cast<char *>(Object::mm->alloc_gc_copy(z_chars_, mem));
|
||||
copy->chars_ = reinterpret_cast<char *>(mm->alloc_gc_copy(z_chars_, mem));
|
||||
strlcpy(copy->chars_, chars_, z_chars_);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue