blob: 653c75cb084b850080131e08e6c77a852cfc97f9 [file] [log] [blame] [edit]
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <executorch/devtools/etdump/emitter.h>
#include <cstdint>
#include <cstring>
#include <executorch/devtools/etdump/etdump_flatcc.h>
#include <executorch/runtime/platform/assert.h>
#include <flatcc/flatcc_builder.h>
using executorch::etdump::internal::ETDumpStaticAllocator;
namespace executorch {
namespace etdump {
namespace internal {
namespace {
int allocator_fn(
void* alloc_context,
flatcc_iovec_t* b,
size_t request,
int zero_fill,
int hint) {
void* p;
size_t n;
ETDumpStaticAllocator* state =
reinterpret_cast<ETDumpStaticAllocator*>(alloc_context);
// This allocator doesn't support freeing memory.
if (request == 0) {
if (b->iov_base) {
b->iov_base = nullptr;
b->iov_len = 0;
}
return 0;
}
switch (hint) {
case flatcc_builder_alloc_ds:
n = 256;
break;
case flatcc_builder_alloc_ht:
/* Should be exact size, or space size is just wasted. */
n = request;
break;
case flatcc_builder_alloc_fs:
n = sizeof(__flatcc_builder_frame_t) * 8;
break;
case flatcc_builder_alloc_us:
n = 64;
break;
case flatcc_builder_alloc_vd:
n = 64;
break;
default:
/*
* We have many small structures - vs stack for tables with few
* elements, and few offset fields in patch log. No need to
* overallocate in case of busy small messages.
*/
n = 32;
break;
}
while (n < request) {
n *= 2;
}
if (b->iov_base != nullptr) {
if (request > b->iov_len) {
// We don't support reallocating larger buffers.
if (((uintptr_t)b->iov_base + b->iov_len) ==
(uintptr_t)&state->data[state->allocated]) {
if ((state->allocated + n - b->iov_len) > state->data_size) {
return -1;
}
state->allocated += n - b->iov_len;
} else {
if ((state->allocated + n) > state->data_size) {
return -1;
}
memcpy((void*)&state->data[state->allocated], b->iov_base, b->iov_len);
b->iov_base = &state->data[state->allocated];
state->allocated += n;
}
if (zero_fill) {
memset((uint8_t*)b->iov_base + b->iov_len, 0, n - b->iov_len);
}
b->iov_len = n;
}
// Ignore request to resize buffers down.
return 0;
}
if ((state->allocated + n) > state->data_size) {
return -1;
}
p = &state->data[state->allocated];
state->allocated += n;
if (zero_fill) {
memset((void*)p, 0, n);
}
b->iov_base = p;
b->iov_len = n;
return 0;
}
// This emitter implementation emits to a fixed size buffer and will fail if it
// runs out of room on either end.
int emitter_fn(
void* emit_context,
const flatcc_iovec_t* iov,
int iov_count,
flatbuffers_soffset_t offset,
size_t len) {
ETDumpStaticAllocator* E =
reinterpret_cast<ETDumpStaticAllocator*>(emit_context);
uint8_t* p;
if (offset < 0) {
if (len > E->front_left) {
return -1;
}
E->front_cursor -= len;
E->front_left -= len;
p = E->front_cursor;
} else {
ET_CHECK_MSG(
0, "Moving the back pointer is currently not supported in ETDump.");
}
while (iov_count--) {
memcpy(p, iov->iov_base, iov->iov_len);
p += iov->iov_len;
++iov;
}
return 0;
}
} // namespace
int etdump_flatcc_custom_init(
flatcc_builder_t* builder,
struct ETDumpStaticAllocator* alloc) {
return flatcc_builder_custom_init(
builder, emitter_fn, alloc, allocator_fn, alloc);
}
} // namespace internal
} // namespace etdump
} // namespace executorch