From 8cb13d7250fbfe648f7ad9b2582b86637150cf98 Mon Sep 17 00:00:00 2001 From: Jake Stevens Date: Tue, 30 Sep 2025 18:14:59 -0700 Subject: [PATCH] Update EVal Payload to use pointers for larger objects (#13013) Summary: As noted in the comment, switching to ptrs in the union can save memory. Specifically, the size of this object goes from 24 bytes -> 8 bytes. In this diff, we move to pointers for some of the larger objects. When parsing the flatbuffer, we allocate memory from the method allocator and store this in the EVal. The get* functions then de-reference that pointer. Reviewed By: JacobSzwejbka Differential Revision: D79286076 --- devtools/etdump/tests/etdump_test.cpp | 2 +- .../evalue_util/test/print_evalue_test.cpp | 105 +++++++++++------- .../make_boxed_from_unboxed_functor_test.cpp | 4 +- kernels/prim_ops/test/prim_ops_test.cpp | 35 +++--- runtime/core/evalue.h | 57 +++++----- runtime/core/test/evalue_test.cpp | 9 +- runtime/executor/method.cpp | 47 ++++++-- 7 files changed, 163 insertions(+), 96 deletions(-) diff --git a/devtools/etdump/tests/etdump_test.cpp b/devtools/etdump/tests/etdump_test.cpp index d095844986f..fd35caca557 100644 --- a/devtools/etdump/tests/etdump_test.cpp +++ b/devtools/etdump/tests/etdump_test.cpp @@ -345,7 +345,7 @@ TEST_F(ProfilerETDumpTest, DebugEventTensorList) { EValue* values_p[2] = {&evalue_1, &evalue_2}; BoxedEvalueList a_box(values_p, storage, 2); - EValue evalue(a_box); + EValue evalue(&a_box); evalue.tag = Tag::ListTensor; etdump_gen[i]->create_event_block("test_block"); diff --git a/extension/evalue_util/test/print_evalue_test.cpp b/extension/evalue_util/test/print_evalue_test.cpp index 242cb0af224..a7e300ff383 100644 --- a/extension/evalue_util/test/print_evalue_test.cpp +++ b/extension/evalue_util/test/print_evalue_test.cpp @@ -154,21 +154,24 @@ TEST(PrintEvalueTest, NaNDouble) { TEST(PrintEvalueTest, EmptyString) { std::string str = ""; - EValue value(str.c_str(), str.size()); + ArrayRef str_ref(const_cast(str.c_str()), str.size()); + EValue value(&str_ref); expect_output(value, "\"\""); } TEST(PrintEvalueTest, BasicString) { // No escaping required. std::string str = "Test Data"; - EValue value(str.c_str(), str.size()); + ArrayRef str_ref(const_cast(str.c_str()), str.size()); + EValue value(&str_ref); expect_output(value, "\"Test Data\""); } TEST(PrintEvalueTest, EscapedString) { // Contains characters that need to be escaped. std::string str = "double quote: \" backslash: \\"; - EValue value(str.c_str(), str.size()); + ArrayRef str_ref(const_cast(str.c_str()), str.size()); + EValue value(&str_ref); expect_output(value, "\"double quote: \\\" backslash: \\\\\""); } @@ -267,31 +270,38 @@ TEST(PrintEvalueTest, UnelidedBoolLists) { // case; the other scalar types use the same underlying code, so they don't // need to test this again. { - EValue value(ArrayRef(list.data(), static_cast(0ul))); + ArrayRef bool_ref(list.data(), static_cast(0ul)); + EValue value(&bool_ref); expect_output(value, "(len=0)[]"); } { - EValue value(ArrayRef(list.data(), 1)); + ArrayRef bool_ref(list.data(), 1); + EValue value(&bool_ref); expect_output(value, "(len=1)[True]"); } { - EValue value(ArrayRef(list.data(), 2)); + ArrayRef bool_ref(list.data(), 2); + EValue value(&bool_ref); expect_output(value, "(len=2)[True, False]"); } { - EValue value(ArrayRef(list.data(), 3)); + ArrayRef bool_ref(list.data(), 3); + EValue value(&bool_ref); expect_output(value, "(len=3)[True, False, True]"); } { - EValue value(ArrayRef(list.data(), 4)); + ArrayRef bool_ref(list.data(), 4); + EValue value(&bool_ref); expect_output(value, "(len=4)[True, False, True, False]"); } { - EValue value(ArrayRef(list.data(), 5)); + ArrayRef bool_ref(list.data(), 5); + EValue value(&bool_ref); expect_output(value, "(len=5)[True, False, True, False, True]"); } { - EValue value(ArrayRef(list.data(), 6)); + ArrayRef bool_ref(list.data(), 6); + EValue value(&bool_ref); expect_output(value, "(len=6)[True, False, True, False, True, False]"); } } @@ -302,16 +312,19 @@ TEST(PrintEvalueTest, ElidedBoolLists) { { // Default edge items is 3, so the shortest elided list length is 7. - EValue value(ArrayRef(list.data(), 7)); + ArrayRef bool_ref(list.data(), 7); + EValue value(&bool_ref); expect_output(value, "(len=7)[True, False, True, ..., True, False, True]"); } { - EValue value(ArrayRef(list.data(), 8)); + ArrayRef bool_ref(list.data(), 8); + EValue value(&bool_ref); expect_output(value, "(len=8)[True, False, True, ..., False, True, False]"); } { // Multi-digit length. - EValue value(ArrayRef(list.data(), 10)); + ArrayRef bool_ref(list.data(), 10); + EValue value(&bool_ref); expect_output( value, "(len=10)[True, False, True, ..., False, True, False]"); } @@ -342,19 +355,19 @@ TEST(PrintEvalueTest, UnelidedIntLists) { { BoxedEvalueList list( wrapped_values.data(), unwrapped_values.data(), 0); - EValue value(list); + EValue value(&list); expect_output(value, "(len=0)[]"); } { BoxedEvalueList list( wrapped_values.data(), unwrapped_values.data(), 3); - EValue value(list); + EValue value(&list); expect_output(value, "(len=3)[-2, -1, 0]"); } { BoxedEvalueList list( wrapped_values.data(), unwrapped_values.data(), 6); - EValue value(list); + EValue value(&list); expect_output(value, "(len=6)[-2, -1, 0, 1, 2, 3]"); } } @@ -392,20 +405,20 @@ TEST(PrintEvalueTest, ElidedIntLists) { // Default edge items is 3, so the shortest elided list length is 7. BoxedEvalueList list( wrapped_values.data(), unwrapped_values.data(), 7); - EValue value(list); + EValue value(&list); expect_output(value, "(len=7)[-4, -3, -2, ..., 0, 1, 2]"); } { BoxedEvalueList list( wrapped_values.data(), unwrapped_values.data(), 8); - EValue value(list); + EValue value(&list); expect_output(value, "(len=8)[-4, -3, -2, ..., 1, 2, 3]"); } { // Multi-digit length. BoxedEvalueList list( wrapped_values.data(), unwrapped_values.data(), 10); - EValue value(list); + EValue value(&list); expect_output(value, "(len=10)[-4, -3, -2, ..., 3, 4, 5]"); } } @@ -419,15 +432,18 @@ TEST(PrintEvalueTest, UnelidedDoubleLists) { std::array list = {-2.2, -1, 0, INFINITY, NAN, 3.3}; { - EValue value(ArrayRef(list.data(), static_cast(0ul))); + ArrayRef double_ref(list.data(), static_cast(0ul)); + EValue value(&double_ref); expect_output(value, "(len=0)[]"); } { - EValue value(ArrayRef(list.data(), 3)); + ArrayRef double_ref(list.data(), 3); + EValue value(&double_ref); expect_output(value, "(len=3)[-2.2, -1., 0.]"); } { - EValue value(ArrayRef(list.data(), 6)); + ArrayRef double_ref(list.data(), 6); + EValue value(&double_ref); expect_output(value, "(len=6)[-2.2, -1., 0., inf, nan, 3.3]"); } } @@ -438,16 +454,19 @@ TEST(PrintEvalueTest, ElidedDoubleLists) { { // Default edge items is 3, so the shortest elided list length is 7. - EValue value(ArrayRef(list.data(), 7)); + ArrayRef double_ref(list.data(), 7); + EValue value(&double_ref); expect_output(value, "(len=7)[-4.4, -3., -2.2, ..., 0., inf, nan]"); } { - EValue value(ArrayRef(list.data(), 8)); + ArrayRef double_ref(list.data(), 8); + EValue value(&double_ref); expect_output(value, "(len=8)[-4.4, -3., -2.2, ..., inf, nan, 3.3]"); } { // Multi-digit length. - EValue value(ArrayRef(list.data(), 10)); + ArrayRef double_ref(list.data(), 10); + EValue value(&double_ref); expect_output(value, "(len=10)[-4.4, -3., -2.2, ..., 3.3, 4., 5.5]"); } } @@ -503,7 +522,7 @@ void expect_tensor_list_output(size_t num_tensors, const char* expected) { ASSERT_LE(num_tensors, wrapped_values.size()); BoxedEvalueList list( wrapped_values.data(), unwrapped_values, num_tensors); - EValue value(list); + EValue value(&list); expect_output(value, expected); } @@ -579,7 +598,7 @@ void expect_list_optional_tensor_output( ASSERT_LE(num_tensors, wrapped_values.size()); BoxedEvalueList> list( wrapped_values.data(), unwrapped_values, num_tensors); - EValue value(list); + EValue value(&list); expect_output(value, expected); } @@ -628,7 +647,8 @@ TEST(PrintEvalueTest, UnknownTag) { TEST(PrintEvalueTest, EdgeItemsOverride) { std::array list = {-3.0, -2.2, -1, 0, 3.3, 4.0, 5.5}; - EValue value(ArrayRef(list.data(), 7)); + ArrayRef double_ref(list.data(), 7); + EValue value(&double_ref); { // Default edge items is 3, so this should elide. @@ -653,7 +673,8 @@ TEST(PrintEvalueTest, EdgeItemsOverride) { TEST(PrintEvalueTest, EdgeItemsDefaults) { std::array list = {-3.0, -2.2, -1, 0, 3.3, 4.0, 5.5}; - EValue value(ArrayRef(list.data(), 7)); + ArrayRef double_ref(list.data(), 7); + EValue value(&double_ref); { // Default edge items is 3, so this should elide. @@ -680,7 +701,8 @@ TEST(PrintEvalueTest, EdgeItemsDefaults) { TEST(PrintEvalueTest, EdgeItemsSingleStream) { std::array list = {-3.0, -2.2, -1, 0, 3.3, 4.0, 5.5}; - EValue value(ArrayRef(list.data(), 7)); + ArrayRef double_ref(list.data(), 7); + EValue value(&double_ref); std::ostringstream os_before; // Print to the same stream multiple times, showing that evalue_edge_items @@ -750,7 +772,8 @@ TEST(PrintEvalueTest, ListWrapping) { { // Should elide by default and print on a single line. - EValue value(ArrayRef(list.data(), list.size())); + ArrayRef double_ref(list.data(), list.size()); + EValue value(&double_ref); std::ostringstream os; os << value; @@ -759,7 +782,8 @@ TEST(PrintEvalueTest, ListWrapping) { { // Exactly the per-line length should not wrap when increasing the number of // edge items to disable elision. - EValue value(ArrayRef(list.data(), kItemsPerLine)); + ArrayRef double_ref(list.data(), kItemsPerLine); + EValue value(&double_ref); std::ostringstream os; os << torch::executor::util::evalue_edge_items(1000) << value; @@ -768,7 +792,8 @@ TEST(PrintEvalueTest, ListWrapping) { } { // One more than the per-line length should wrap; no elision. - EValue value(ArrayRef(list.data(), kItemsPerLine + 1)); + ArrayRef double_ref(list.data(), kItemsPerLine + 1); + EValue value(&double_ref); std::ostringstream os; os << torch::executor::util::evalue_edge_items(1000) << value; @@ -781,7 +806,8 @@ TEST(PrintEvalueTest, ListWrapping) { } { // Exactly twice the per-line length, without elision. - EValue value(ArrayRef(list.data(), kItemsPerLine * 2)); + ArrayRef double_ref(list.data(), kItemsPerLine * 2); + EValue value(&double_ref); std::ostringstream os; os << torch::executor::util::evalue_edge_items(1000) << value; @@ -795,7 +821,8 @@ TEST(PrintEvalueTest, ListWrapping) { } { // Exactly one whole line, with elision. - EValue value(ArrayRef(list.data(), kItemsPerLine * 3)); + ArrayRef double_ref(list.data(), kItemsPerLine * 3); + EValue value(&double_ref); std::ostringstream os; os << torch::executor::util::evalue_edge_items(kItemsPerLine) << value; @@ -810,7 +837,8 @@ TEST(PrintEvalueTest, ListWrapping) { } { // Edge item count slightly larger than per-line length, with elision. - EValue value(ArrayRef(list.data(), kItemsPerLine * 3)); + ArrayRef double_ref(list.data(), kItemsPerLine * 3); + EValue value(&double_ref); std::ostringstream os; os << torch::executor::util::evalue_edge_items(kItemsPerLine + 1) << value; @@ -829,7 +857,8 @@ TEST(PrintEvalueTest, ListWrapping) { } { // Large wrapped, ragged, elided example. - EValue value(ArrayRef(list.data(), list.size())); + ArrayRef double_ref(list.data(), list.size()); + EValue value(&double_ref); std::ostringstream os; os << torch::executor::util::evalue_edge_items(33) << value; @@ -946,7 +975,7 @@ TEST(PrintEvalueTest, WrappedTensorLists) { // Demonstrate the formatting when printing a list with multiple tensors. BoxedEvalueList list( wrapped_values.data(), unwrapped_values, wrapped_values.size()); - EValue value(list); + EValue value(&list); std::ostringstream os; os << torch::executor::util::evalue_edge_items(15) << value; diff --git a/extension/kernel_util/test/make_boxed_from_unboxed_functor_test.cpp b/extension/kernel_util/test/make_boxed_from_unboxed_functor_test.cpp index 2c7bb1f9e2b..b9176cfc826 100644 --- a/extension/kernel_util/test/make_boxed_from_unboxed_functor_test.cpp +++ b/extension/kernel_util/test/make_boxed_from_unboxed_functor_test.cpp @@ -133,7 +133,7 @@ TEST_F(MakeBoxedFromUnboxedFunctorTest, UnboxArrayRef) { EValue evalues[2] = {storage[0], storage[1]}; EValue* values_p[2] = {&evalues[0], &evalues[1]}; BoxedEvalueList a_box(values_p, storage, 2); - EValue boxed_array_ref(a_box); + EValue boxed_array_ref(&a_box); // prepare out tensor. EValue out(tf.zeros({5})); @@ -186,7 +186,7 @@ TEST_F(MakeBoxedFromUnboxedFunctorTest, UnboxOptionalArrayRef) { EValue evalues[2] = {EValue(tf.ones({5})), EValue()}; EValue* values_p[2] = {&evalues[0], &evalues[1]}; BoxedEvalueList> a_box(values_p, storage, 2); - EValue boxed_array_ref(a_box); + EValue boxed_array_ref(&a_box); // prepare out tensor. EValue out(tf.zeros({5})); diff --git a/kernels/prim_ops/test/prim_ops_test.cpp b/kernels/prim_ops/test/prim_ops_test.cpp index 938b49bf58f..1ccb2c27ce5 100644 --- a/kernels/prim_ops/test/prim_ops_test.cpp +++ b/kernels/prim_ops/test/prim_ops_test.cpp @@ -434,8 +434,9 @@ TEST_F(RegisterPrimOpsTest, TestETView) { EValue* size_wrapped_vals[3] = { &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; int64_t size_unwrapped_vals[3] = {0, 0, 0}; - EValue size_int_list_evalue = EValue( - BoxedEvalueList(size_wrapped_vals, size_unwrapped_vals, 3)); + BoxedEvalueList size_boxed_list( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list); int64_t bad_size1[3] = {-1, 3, -1}; // two inferred dimensions EValue bad_size_as_evals1[3] = { @@ -443,8 +444,9 @@ TEST_F(RegisterPrimOpsTest, TestETView) { EValue* bad_size_wrapped_vals1[3] = { &bad_size_as_evals1[0], &bad_size_as_evals1[1], &bad_size_as_evals1[2]}; int64_t bad_size_unwrapped_vals1[3] = {0, 0, 0}; - EValue bad_size_int_list_evalue1 = EValue(BoxedEvalueList( - bad_size_wrapped_vals1, bad_size_unwrapped_vals1, 3)); + BoxedEvalueList bad_size_boxed_list1( + bad_size_wrapped_vals1, bad_size_unwrapped_vals1, 3); + EValue bad_size_int_list_evalue1 = EValue(&bad_size_boxed_list1); int64_t bad_size2[3] = {-2, -3, 1}; // negative size not supported EValue bad_size_as_evals2[3] = { @@ -452,8 +454,9 @@ TEST_F(RegisterPrimOpsTest, TestETView) { EValue* bad_size_wrapped_vals2[3] = { &bad_size_as_evals2[0], &bad_size_as_evals2[1], &bad_size_as_evals2[2]}; int64_t bad_size_unwrapped_vals2[3] = {0, 0, 0}; - EValue bad_size_int_list_evalue2 = EValue(BoxedEvalueList( - bad_size_wrapped_vals2, bad_size_unwrapped_vals2, 3)); + BoxedEvalueList bad_size_boxed_list2( + bad_size_wrapped_vals2, bad_size_unwrapped_vals2, 3); + EValue bad_size_int_list_evalue2 = EValue(&bad_size_boxed_list2); // *************************************************************************** // Make outs for tests @@ -525,8 +528,9 @@ TEST_F(RegisterPrimOpsTest, TestETViewDynamic) { EValue* size_wrapped_vals[3] = { &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; int64_t size_unwrapped_vals[3] = {0, 0, 0}; - EValue size_int_list_evalue = EValue( - BoxedEvalueList(size_wrapped_vals, size_unwrapped_vals, 3)); + BoxedEvalueList size_boxed_list_2( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list_2); #ifdef USE_ATEN_LIB // ATen mode tensors don't need dynamism specification. @@ -560,8 +564,9 @@ TEST_F(RegisterPrimOpsTest, TestETViewEmpty) { EValue* size_wrapped_vals[3] = { &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; int64_t size_unwrapped_vals[3] = {0, 0, 0}; - EValue size_int_list_evalue = EValue( - BoxedEvalueList(size_wrapped_vals, size_unwrapped_vals, 3)); + BoxedEvalueList size_boxed_list_3( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list_3); int64_t bad_size[3] = {0, 1, -1}; // bad size: cannot infer with 0 EValue bad_size_as_evals[3] = { @@ -569,8 +574,9 @@ TEST_F(RegisterPrimOpsTest, TestETViewEmpty) { EValue* bad_size_wrapped_vals[3] = { &bad_size_as_evals[0], &bad_size_as_evals[1], &bad_size_as_evals[2]}; int64_t bad_size_unwrapped_vals[3] = {0, 0, 0}; - EValue bad_size_int_list_evalue = EValue(BoxedEvalueList( - bad_size_wrapped_vals, bad_size_unwrapped_vals, 3)); + BoxedEvalueList bad_size_boxed_list( + bad_size_wrapped_vals, bad_size_unwrapped_vals, 3); + EValue bad_size_int_list_evalue = EValue(&bad_size_boxed_list); auto out = tf.make({3, 1, 0}, {}, {}); EValue out_evalue = EValue(out); @@ -880,8 +886,9 @@ TEST_F(RegisterPrimOpsTest, TestInvalidProgramErrorOnShortStack) { EValue* size_wrapped_vals[3] = { &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; int64_t size_unwrapped_vals[3] = {0, 0, 0}; - EValue size_int_list_evalue = EValue( - BoxedEvalueList(size_wrapped_vals, size_unwrapped_vals, 3)); + BoxedEvalueList size_boxed_list_4( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list_4); EValue* stack[2] = {&self_evalue, &size_int_list_evalue}; diff --git a/runtime/core/evalue.h b/runtime/core/evalue.h index 6f1cc5f06db..0cea86dc30c 100644 --- a/runtime/core/evalue.h +++ b/runtime/core/evalue.h @@ -94,15 +94,14 @@ struct EValue { int64_t as_int; double as_double; bool as_bool; - // TODO(jakeszwe): convert back to pointers to optimize size of this - // struct - executorch::aten::ArrayRef as_string; - executorch::aten::ArrayRef as_double_list; - executorch::aten::ArrayRef as_bool_list; - BoxedEvalueList as_int_list; - BoxedEvalueList as_tensor_list; - BoxedEvalueList> - as_list_optional_tensor; + + executorch::aten::ArrayRef* as_string_ptr; + executorch::aten::ArrayRef* as_double_list_ptr; + executorch::aten::ArrayRef* as_bool_list_ptr; + BoxedEvalueList* as_int_list_ptr; + BoxedEvalueList* as_tensor_list_ptr; + BoxedEvalueList>* + as_list_optional_tensor_ptr; } copyable_union; // Since a Tensor just holds a TensorImpl*, there's no value to use Tensor* @@ -280,9 +279,8 @@ struct EValue { } /****** String Type ******/ - /*implicit*/ EValue(const char* s, size_t size) : tag(Tag::String) { - payload.copyable_union.as_string = - executorch::aten::ArrayRef(s, size); + /*implicit*/ EValue(executorch::aten::ArrayRef* s) : tag(Tag::String) { + payload.copyable_union.as_string_ptr = s; } bool isString() const { @@ -292,13 +290,13 @@ struct EValue { std::string_view toString() const { ET_CHECK_MSG(isString(), "EValue is not a String."); return std::string_view( - payload.copyable_union.as_string.data(), - payload.copyable_union.as_string.size()); + payload.copyable_union.as_string_ptr->data(), + payload.copyable_union.as_string_ptr->size()); } /****** Int List Type ******/ - /*implicit*/ EValue(BoxedEvalueList i) : tag(Tag::ListInt) { - payload.copyable_union.as_int_list = i; + /*implicit*/ EValue(BoxedEvalueList* i) : tag(Tag::ListInt) { + payload.copyable_union.as_int_list_ptr = i; } bool isIntList() const { @@ -307,12 +305,13 @@ struct EValue { executorch::aten::ArrayRef toIntList() const { ET_CHECK_MSG(isIntList(), "EValue is not an Int List."); - return payload.copyable_union.as_int_list.get(); + return (payload.copyable_union.as_int_list_ptr)->get(); } /****** Bool List Type ******/ - /*implicit*/ EValue(executorch::aten::ArrayRef b) : tag(Tag::ListBool) { - payload.copyable_union.as_bool_list = b; + /*implicit*/ EValue(executorch::aten::ArrayRef* b) + : tag(Tag::ListBool) { + payload.copyable_union.as_bool_list_ptr = b; } bool isBoolList() const { @@ -321,13 +320,13 @@ struct EValue { executorch::aten::ArrayRef toBoolList() const { ET_CHECK_MSG(isBoolList(), "EValue is not a Bool List."); - return payload.copyable_union.as_bool_list; + return *(payload.copyable_union.as_bool_list_ptr); } /****** Double List Type ******/ - /*implicit*/ EValue(executorch::aten::ArrayRef d) + /*implicit*/ EValue(executorch::aten::ArrayRef* d) : tag(Tag::ListDouble) { - payload.copyable_union.as_double_list = d; + payload.copyable_union.as_double_list_ptr = d; } bool isDoubleList() const { @@ -336,13 +335,13 @@ struct EValue { executorch::aten::ArrayRef toDoubleList() const { ET_CHECK_MSG(isDoubleList(), "EValue is not a Double List."); - return payload.copyable_union.as_double_list; + return *(payload.copyable_union.as_double_list_ptr); } /****** Tensor List Type ******/ - /*implicit*/ EValue(BoxedEvalueList t) + /*implicit*/ EValue(BoxedEvalueList* t) : tag(Tag::ListTensor) { - payload.copyable_union.as_tensor_list = t; + payload.copyable_union.as_tensor_list_ptr = t; } bool isTensorList() const { @@ -351,14 +350,14 @@ struct EValue { executorch::aten::ArrayRef toTensorList() const { ET_CHECK_MSG(isTensorList(), "EValue is not a Tensor List."); - return payload.copyable_union.as_tensor_list.get(); + return payload.copyable_union.as_tensor_list_ptr->get(); } /****** List Optional Tensor Type ******/ /*implicit*/ EValue( - BoxedEvalueList> t) + BoxedEvalueList>* t) : tag(Tag::ListOptionalTensor) { - payload.copyable_union.as_list_optional_tensor = t; + payload.copyable_union.as_list_optional_tensor_ptr = t; } bool isListOptionalTensor() const { @@ -367,7 +366,7 @@ struct EValue { executorch::aten::ArrayRef> toListOptionalTensor() const { - return payload.copyable_union.as_list_optional_tensor.get(); + return payload.copyable_union.as_list_optional_tensor_ptr->get(); } /****** ScalarType Type ******/ diff --git a/runtime/core/test/evalue_test.cpp b/runtime/core/test/evalue_test.cpp index 06cdc40ad98..f04745187bb 100644 --- a/runtime/core/test/evalue_test.cpp +++ b/runtime/core/test/evalue_test.cpp @@ -166,7 +166,9 @@ TEST_F(EValueTest, ToScalarType) { } TEST_F(EValueTest, toString) { - const EValue e("foo", 3); + auto string_ref = + std::make_unique>("foo", 3); + const EValue e(string_ref.get()); EXPECT_TRUE(e.isString()); EXPECT_FALSE(e.isNone()); @@ -218,11 +220,12 @@ TEST_F(EValueTest, toOptionalTensorList) { EValue* values_p[2] = {&values[0], &values[1]}; std::optional storage[2]; // wrap in array ref - BoxedEvalueList> a( + auto boxed_list = std::make_unique< + BoxedEvalueList>>( values_p, storage, 2); // create Evalue - EValue e(a); + EValue e(boxed_list.get()); e.tag = Tag::ListOptionalTensor; EXPECT_TRUE(e.isListOptionalTensor()); diff --git a/runtime/executor/method.cpp b/runtime/executor/method.cpp index 65a47594c8d..ccb88a03818 100644 --- a/runtime/executor/method.cpp +++ b/runtime/executor/method.cpp @@ -507,8 +507,12 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { j); evalp_list[j] = &values_[static_cast(value_index)]; } - new (&values_[i]) EValue( - BoxedEvalueList(evalp_list, int_list, items->size())); + auto* boxed_list_mem = + memory_manager_->method_allocator() + ->allocateInstance>(); + auto boxed_list = new (boxed_list_mem) + BoxedEvalueList(evalp_list, int_list, items->size()); + new (&values_[i]) EValue(boxed_list); } break; case executorch_flatbuffer::KernelTypes::BoolList: { const auto items = @@ -525,8 +529,12 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { // portable here we need to allocate a new array of bool and copy cast // the flatbuffer data into it, but because of how exceptionally rare // this case is its low prio TODO: jakeszwe - new (&values_[i]) EValue(executorch::aten::ArrayRef( - (const bool*)items->data(), items->size())); + auto* bool_list_mem = + memory_manager_->method_allocator() + ->allocateInstance>(); + auto bool_list = new (bool_list_mem) executorch::aten::ArrayRef( + (const bool*)items->data(), items->size()); + new (&values_[i]) EValue(bool_list); } break; case executorch_flatbuffer::KernelTypes::DoubleList: { const auto items = @@ -536,8 +544,12 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { InvalidProgram, "Missing list at index %" ET_PRIsize_t, i); - new (&values_[i]) EValue( - executorch::aten::ArrayRef(items->data(), items->size())); + auto* double_list_mem = + memory_manager_->method_allocator() + ->allocateInstance>(); + auto double_list = new (double_list_mem) + executorch::aten::ArrayRef(items->data(), items->size()); + new (&values_[i]) EValue(double_list); } break; case executorch_flatbuffer::KernelTypes::String: { const auto fb_str = @@ -548,7 +560,12 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { InvalidProgram, "Missing string at index %" ET_PRIsize_t, i); - new (&values_[i]) EValue(fb_str->c_str(), fb_str->size()); + auto* char_list_mem = + memory_manager_->method_allocator() + ->allocateInstance>(); + auto char_list = new (char_list_mem) + executorch::aten::ArrayRef(fb_str->c_str(), fb_str->size()); + new (&values_[i]) EValue(char_list); } break; case executorch_flatbuffer::KernelTypes::Tensor: { auto t = deserialization::parseTensor( @@ -588,7 +605,12 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { static_cast(tensors.error())); return tensors.error(); } - new (&values_[i]) EValue(tensors.get()); + auto* boxed_tensor_list_mem = + memory_manager_->method_allocator() + ->allocateInstance>(); + auto boxed_tensor_list = new (boxed_tensor_list_mem) + BoxedEvalueList(std::move(tensors.get())); + new (&values_[i]) EValue(boxed_tensor_list); } break; case executorch_flatbuffer::KernelTypes::OptionalTensorList: { const auto items = @@ -612,7 +634,14 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { static_cast(tensors.error())); return tensors.error(); } - new (&values_[i]) EValue(tensors.get()); + auto* boxed_optional_tensor_list_mem = + memory_manager_->method_allocator() + ->allocateInstance< + BoxedEvalueList>>(); + auto boxed_optional_tensor_list = new (boxed_optional_tensor_list_mem) + BoxedEvalueList>( + std::move(tensors.get())); + new (&values_[i]) EValue(boxed_optional_tensor_list); } break; default: // flatbuffer enums start at 0, but they generate a hidden NONE enum