1 /*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 #include <executorch/devtools/etdump/emitter.h>
10
11 #include <cstdint>
12 #include <cstring>
13
14 #include <executorch/devtools/etdump/etdump_flatcc.h>
15 #include <executorch/runtime/platform/assert.h>
16
17 #include <flatcc/flatcc_builder.h>
18
19 using executorch::etdump::internal::ETDumpStaticAllocator;
20
21 namespace executorch {
22 namespace etdump {
23 namespace internal {
24
25 namespace {
26
allocator_fn(void * alloc_context,flatcc_iovec_t * b,size_t request,int zero_fill,int hint)27 int allocator_fn(
28 void* alloc_context,
29 flatcc_iovec_t* b,
30 size_t request,
31 int zero_fill,
32 int hint) {
33 void* p;
34 size_t n;
35
36 ETDumpStaticAllocator* state =
37 reinterpret_cast<ETDumpStaticAllocator*>(alloc_context);
38
39 // This allocator doesn't support freeing memory.
40 if (request == 0) {
41 if (b->iov_base) {
42 b->iov_base = nullptr;
43 b->iov_len = 0;
44 }
45 return 0;
46 }
47
48 switch (hint) {
49 case flatcc_builder_alloc_ds:
50 n = 256;
51 break;
52 case flatcc_builder_alloc_ht:
53 /* Should be exact size, or space size is just wasted. */
54 n = request;
55 break;
56 case flatcc_builder_alloc_fs:
57 n = sizeof(__flatcc_builder_frame_t) * 8;
58 break;
59 case flatcc_builder_alloc_us:
60 n = 64;
61 break;
62 case flatcc_builder_alloc_vd:
63 n = 64;
64 break;
65 default:
66 /*
67 * We have many small structures - vs stack for tables with few
68 * elements, and few offset fields in patch log. No need to
69 * overallocate in case of busy small messages.
70 */
71 n = 32;
72 break;
73 }
74
75 while (n < request) {
76 n *= 2;
77 }
78
79 if (b->iov_base != nullptr) {
80 if (request > b->iov_len) {
81 // We don't support reallocating larger buffers.
82 if (((uintptr_t)b->iov_base + b->iov_len) ==
83 (uintptr_t)&state->data[state->allocated]) {
84 if ((state->allocated + n - b->iov_len) > state->data_size) {
85 return -1;
86 }
87 state->allocated += n - b->iov_len;
88 } else {
89 if ((state->allocated + n) > state->data_size) {
90 return -1;
91 }
92 memcpy((void*)&state->data[state->allocated], b->iov_base, b->iov_len);
93 b->iov_base = &state->data[state->allocated];
94 state->allocated += n;
95 }
96 if (zero_fill) {
97 memset((uint8_t*)b->iov_base + b->iov_len, 0, n - b->iov_len);
98 }
99 b->iov_len = n;
100 }
101
102 // Ignore request to resize buffers down.
103 return 0;
104 }
105
106 if ((state->allocated + n) > state->data_size) {
107 return -1;
108 }
109
110 p = &state->data[state->allocated];
111 state->allocated += n;
112
113 if (zero_fill) {
114 memset((void*)p, 0, n);
115 }
116
117 b->iov_base = p;
118 b->iov_len = n;
119
120 return 0;
121 }
122
123 // This emitter implementation emits to a fixed size buffer and will fail if it
124 // runs out of room on either end.
emitter_fn(void * emit_context,const flatcc_iovec_t * iov,int iov_count,flatbuffers_soffset_t offset,size_t len)125 int emitter_fn(
126 void* emit_context,
127 const flatcc_iovec_t* iov,
128 int iov_count,
129 flatbuffers_soffset_t offset,
130 size_t len) {
131 ETDumpStaticAllocator* E =
132 reinterpret_cast<ETDumpStaticAllocator*>(emit_context);
133 uint8_t* p;
134
135 if (offset < 0) {
136 if (len > E->front_left) {
137 return -1;
138 }
139 E->front_cursor -= len;
140 E->front_left -= len;
141 p = E->front_cursor;
142 } else {
143 ET_CHECK_MSG(
144 0, "Moving the back pointer is currently not supported in ETDump.");
145 }
146
147 while (iov_count--) {
148 memcpy(p, iov->iov_base, iov->iov_len);
149 p += iov->iov_len;
150 ++iov;
151 }
152
153 return 0;
154 }
155
156 } // namespace
157
etdump_flatcc_custom_init(flatcc_builder_t * builder,struct ETDumpStaticAllocator * alloc)158 int etdump_flatcc_custom_init(
159 flatcc_builder_t* builder,
160 struct ETDumpStaticAllocator* alloc) {
161 return flatcc_builder_custom_init(
162 builder, emitter_fn, alloc, allocator_fn, alloc);
163 }
164
165 } // namespace internal
166 } // namespace etdump
167 } // namespace executorch
168