@@ -144,13 +144,56 @@ Result<executorch_flatbuffer::ExecutionPlan*> get_execution_plan(
144144 const executorch_flatbuffer::Program* flatbuffer_program =
145145 executorch_flatbuffer::GetProgram (program_data->data ());
146146
147- // The FreeableBuffer owns the data that flatbuffer_program points into. Also
148- // keep a pointer to the loader so it can load more segments when necessary.
149- return Program (
150- loader,
151- segment_base_offset,
152- std::move (program_data.get ()),
153- flatbuffer_program);
147+ // Constant data may live inside the flatbuffer data (constant_buffer) or in a
148+ // separate segment (constant_segment). It should not be in both.
149+ const auto & constant_buffer = flatbuffer_program->constant_buffer ();
150+ const auto & constant_segment = flatbuffer_program->constant_segment ();
151+
152+ // Check if the constant data is inside a separate segment.
153+ if (constant_segment != nullptr && constant_segment->offsets ()->size () > 0 ) {
154+ ET_CHECK_OR_RETURN_ERROR (
155+ constant_buffer->size () == 0 ,
156+ InvalidState,
157+ " constant_buffer contains %u items, constant_segment.offsets contains %u items. Only one should be used." ,
158+ constant_buffer->size (),
159+ constant_segment->offsets ()->size ());
160+
161+ // Load constant segment.
162+ // TODO(T171839323): Add test for segment_index > num available segments.
163+ ET_CHECK_OR_RETURN_ERROR (
164+ constant_segment->segment_index () <
165+ flatbuffer_program->segments ()->size (),
166+ InvalidArgument,
167+ " Constant segment index %d invalid for program segments range %d" ,
168+ constant_segment->segment_index (),
169+ flatbuffer_program->segments ()->size ());
170+
171+ const executorch_flatbuffer::DataSegment* data_segment =
172+ flatbuffer_program->segments ()->Get (constant_segment->segment_index ());
173+ Result<FreeableBuffer> constant_segment_data = loader->Load (
174+ segment_base_offset + data_segment->offset (), data_segment->size ());
175+ if (!constant_segment_data.ok ()) {
176+ return constant_segment_data.error ();
177+ }
178+ // The FreeableBuffer owns the data that flatbuffer_program points into.
179+ // Also keep a pointer to the loader so it can load more segments when
180+ // necessary.
181+ return Program (
182+ loader,
183+ segment_base_offset,
184+ std::move (program_data.get ()),
185+ flatbuffer_program,
186+ std::move (constant_segment_data.get ()));
187+ } else {
188+ // The constant data is stored inside the flatbuffer, so this program does
189+ // not contain a separate segment for it.
190+ return Program (
191+ loader,
192+ segment_base_offset,
193+ std::move (program_data.get ()),
194+ flatbuffer_program,
195+ /* constant_segment_data=*/ FreeableBuffer{});
196+ }
154197}
155198
156199size_t Program::num_methods () const {
@@ -192,21 +235,67 @@ Result<MethodMeta> Program::method_meta(const char* method_name) const {
192235}
193236
194237Result<const void *> Program::get_constant_buffer_data (
195- size_t buffer_index) const {
238+ size_t buffer_index,
239+ size_t nbytes) const {
196240 auto internal_program =
197241 static_cast <const executorch_flatbuffer::Program*>(internal_program_);
198- size_t size = internal_program->constant_buffer ()->size ();
199- ET_CHECK_OR_RETURN_ERROR (
200- buffer_index < size,
201- InvalidArgument,
202- " Constant buffer %zu out of program buffer range %zu" ,
203- buffer_index,
204- size);
205242
206- const auto & constant_buffer = *internal_program->constant_buffer ();
243+ // Constant data is either in a separate segment (constant_segment_data) and
244+ // loaded during Program::load, or stored inside the flatbuffer data
245+ // (constant_buffer).
246+ if (constant_segment_data_.data () != nullptr ) {
247+ size_t num_elems = internal_program->constant_segment ()->offsets ()->size ();
248+ ET_CHECK_OR_RETURN_ERROR (
249+ buffer_index < num_elems,
250+ InvalidArgument,
251+ " Constant segment buffer index %zu invalid for program constant segment range %zu" ,
252+ buffer_index,
253+ num_elems);
254+
255+ // All constant data is stored in one segment, with each tensor aligned to
256+ // @executorch_tensor_alignment. Tensor offsets are stored in the flatbuffer
257+ // data in Program.constant_segment.offsets.
258+ // The constant data at buffer_index is located at: base address of the
259+ // constant segment + offset for tensor at buffer_index.
260+ uint64_t offset = static_cast <uint64_t >(
261+ (*internal_program->constant_segment ()->offsets ())[buffer_index]);
207262
208- return static_cast <const void *>(
209- constant_buffer[buffer_index]->storage ()->data ());
263+ size_t size = constant_segment_data_.size ();
264+ ET_CHECK_OR_RETURN_ERROR (
265+ offset + nbytes <= size,
266+ InvalidArgument,
267+ " Constant segment offset %" PRIu64
268+ " + size_bytes %zu invalid for program constant segment size %zu" ,
269+ offset,
270+ nbytes,
271+ size);
272+
273+ // Offset is wrt the beginning of the constant segment.
274+ return static_cast <const void *>(
275+ static_cast <const unsigned char *>(constant_segment_data_.data ()) +
276+ offset);
277+ } else {
278+ // Otherwise, the constant data is stored inside Program.constant_buffer.
279+ size_t num_elems = internal_program->constant_buffer ()->size ();
280+ ET_CHECK_OR_RETURN_ERROR (
281+ buffer_index < num_elems,
282+ InvalidArgument,
283+ " Constant buffer index %zu invalid for program constant buffer range %zu" ,
284+ buffer_index,
285+ num_elems);
286+
287+ const auto & constant_buffer = *internal_program->constant_buffer ();
288+
289+ ET_CHECK_OR_RETURN_ERROR (
290+ constant_buffer[buffer_index]->storage ()->size () <= nbytes,
291+ InvalidArgument,
292+ " Constant buffer size %u larger than allocated nbytes %zu" ,
293+ constant_buffer[buffer_index]->storage ()->size (),
294+ nbytes);
295+
296+ return static_cast <const void *>(
297+ constant_buffer[buffer_index]->storage ()->data ());
298+ }
210299}
211300
212301Result<int64_t > Program::get_non_const_buffer_size (
0 commit comments