Skip to content

Commit bdfd20b

Browse files
committed
Serialize FunctionCall into &[u8] instead of Vec<u8>, avoiding unnecessary allocations and copies
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent a6bc615 commit bdfd20b

File tree

10 files changed

+102
-111
lines changed

10 files changed

+102
-111
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/hyperlight_common/src/flatbuffer_wrappers/function_call.rs

+87-97
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use alloc::string::{String, ToString};
1818
use alloc::vec::Vec;
1919

2020
use anyhow::{bail, Error, Result};
21-
use flatbuffers::{size_prefixed_root, WIPOffset};
21+
use flatbuffers::{size_prefixed_root, FlatBufferBuilder, WIPOffset};
2222
#[cfg(feature = "tracing")]
2323
use tracing::{instrument, Span};
2424

@@ -41,7 +41,6 @@ pub enum FunctionCallType {
4141
}
4242

4343
/// `Functioncall` represents a call to a function in the guest or host.
44-
#[derive(Clone)]
4544
pub struct FunctionCall {
4645
/// The function name
4746
pub function_name: String,
@@ -72,91 +71,29 @@ impl FunctionCall {
7271
pub fn function_call_type(&self) -> FunctionCallType {
7372
self.function_call_type.clone()
7473
}
75-
}
7674

77-
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
78-
pub fn validate_guest_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> {
79-
let guest_function_call_fb = size_prefixed_root::<FbFunctionCall>(function_call_buffer)
80-
.map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
81-
match guest_function_call_fb.function_call_type() {
82-
FbFunctionCallType::guest => Ok(()),
83-
other => {
84-
bail!("Invalid function call type: {:?}", other);
85-
}
86-
}
87-
}
88-
89-
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
90-
pub fn validate_host_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> {
91-
let host_function_call_fb = size_prefixed_root::<FbFunctionCall>(function_call_buffer)
92-
.map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
93-
match host_function_call_fb.function_call_type() {
94-
FbFunctionCallType::host => Ok(()),
95-
other => {
96-
bail!("Invalid function call type: {:?}", other);
97-
}
98-
}
99-
}
75+
/// Encodes self into the given builder and returns the encoded data.
76+
pub fn encode<'a>(&self, builder: &'a mut FlatBufferBuilder) -> &'a [u8] {
77+
let function_name = builder.create_string(&self.function_name);
10078

101-
impl TryFrom<&[u8]> for FunctionCall {
102-
type Error = Error;
103-
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
104-
fn try_from(value: &[u8]) -> Result<Self> {
105-
let function_call_fb = size_prefixed_root::<FbFunctionCall>(value)
106-
.map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
107-
let function_name = function_call_fb.function_name();
108-
let function_call_type = match function_call_fb.function_call_type() {
109-
FbFunctionCallType::guest => FunctionCallType::Guest,
110-
FbFunctionCallType::host => FunctionCallType::Host,
111-
other => {
112-
bail!("Invalid function call type: {:?}", other);
113-
}
114-
};
115-
let expected_return_type = function_call_fb.expected_return_type().try_into()?;
116-
117-
let parameters = function_call_fb
118-
.parameters()
119-
.map(|v| {
120-
v.iter()
121-
.map(|p| p.try_into())
122-
.collect::<Result<Vec<ParameterValue>>>()
123-
})
124-
.transpose()?;
125-
126-
Ok(Self {
127-
function_name: function_name.to_string(),
128-
parameters,
129-
function_call_type,
130-
expected_return_type,
131-
})
132-
}
133-
}
134-
135-
impl TryFrom<FunctionCall> for Vec<u8> {
136-
type Error = Error;
137-
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
138-
fn try_from(value: FunctionCall) -> Result<Vec<u8>> {
139-
let mut builder = flatbuffers::FlatBufferBuilder::new();
140-
let function_name = builder.create_string(&value.function_name);
141-
142-
let function_call_type = match value.function_call_type {
79+
let function_call_type = match self.function_call_type {
14380
FunctionCallType::Guest => FbFunctionCallType::guest,
14481
FunctionCallType::Host => FbFunctionCallType::host,
14582
};
14683

147-
let expected_return_type = value.expected_return_type.into();
84+
let expected_return_type = self.expected_return_type.into();
14885

149-
let parameters = match &value.parameters {
86+
let parameters = match &self.parameters {
15087
Some(p) => {
15188
let num_items = p.len();
15289
let mut parameters: Vec<WIPOffset<Parameter>> = Vec::with_capacity(num_items);
15390

15491
for param in p {
15592
match param {
15693
ParameterValue::Int(i) => {
157-
let hlint = hlint::create(&mut builder, &hlintArgs { value: *i });
94+
let hlint = hlint::create(builder, &hlintArgs { value: *i });
15895
let parameter = Parameter::create(
159-
&mut builder,
96+
builder,
16097
&ParameterArgs {
16198
value_type: FbParameterValue::hlint,
16299
value: Some(hlint.as_union_value()),
@@ -165,9 +102,9 @@ impl TryFrom<FunctionCall> for Vec<u8> {
165102
parameters.push(parameter);
166103
}
167104
ParameterValue::UInt(ui) => {
168-
let hluint = hluint::create(&mut builder, &hluintArgs { value: *ui });
105+
let hluint = hluint::create(builder, &hluintArgs { value: *ui });
169106
let parameter = Parameter::create(
170-
&mut builder,
107+
builder,
171108
&ParameterArgs {
172109
value_type: FbParameterValue::hluint,
173110
value: Some(hluint.as_union_value()),
@@ -176,9 +113,9 @@ impl TryFrom<FunctionCall> for Vec<u8> {
176113
parameters.push(parameter);
177114
}
178115
ParameterValue::Long(l) => {
179-
let hllong = hllong::create(&mut builder, &hllongArgs { value: *l });
116+
let hllong = hllong::create(builder, &hllongArgs { value: *l });
180117
let parameter = Parameter::create(
181-
&mut builder,
118+
builder,
182119
&ParameterArgs {
183120
value_type: FbParameterValue::hllong,
184121
value: Some(hllong.as_union_value()),
@@ -187,10 +124,9 @@ impl TryFrom<FunctionCall> for Vec<u8> {
187124
parameters.push(parameter);
188125
}
189126
ParameterValue::ULong(ul) => {
190-
let hlulong =
191-
hlulong::create(&mut builder, &hlulongArgs { value: *ul });
127+
let hlulong = hlulong::create(builder, &hlulongArgs { value: *ul });
192128
let parameter = Parameter::create(
193-
&mut builder,
129+
builder,
194130
&ParameterArgs {
195131
value_type: FbParameterValue::hlulong,
196132
value: Some(hlulong.as_union_value()),
@@ -199,9 +135,9 @@ impl TryFrom<FunctionCall> for Vec<u8> {
199135
parameters.push(parameter);
200136
}
201137
ParameterValue::Float(f) => {
202-
let hlfloat = hlfloat::create(&mut builder, &hlfloatArgs { value: *f });
138+
let hlfloat = hlfloat::create(builder, &hlfloatArgs { value: *f });
203139
let parameter = Parameter::create(
204-
&mut builder,
140+
builder,
205141
&ParameterArgs {
206142
value_type: FbParameterValue::hlfloat,
207143
value: Some(hlfloat.as_union_value()),
@@ -210,10 +146,9 @@ impl TryFrom<FunctionCall> for Vec<u8> {
210146
parameters.push(parameter);
211147
}
212148
ParameterValue::Double(d) => {
213-
let hldouble =
214-
hldouble::create(&mut builder, &hldoubleArgs { value: *d });
149+
let hldouble = hldouble::create(builder, &hldoubleArgs { value: *d });
215150
let parameter = Parameter::create(
216-
&mut builder,
151+
builder,
217152
&ParameterArgs {
218153
value_type: FbParameterValue::hldouble,
219154
value: Some(hldouble.as_union_value()),
@@ -223,9 +158,9 @@ impl TryFrom<FunctionCall> for Vec<u8> {
223158
}
224159
ParameterValue::Bool(b) => {
225160
let hlbool: WIPOffset<hlbool<'_>> =
226-
hlbool::create(&mut builder, &hlboolArgs { value: *b });
161+
hlbool::create(builder, &hlboolArgs { value: *b });
227162
let parameter = Parameter::create(
228-
&mut builder,
163+
builder,
229164
&ParameterArgs {
230165
value_type: FbParameterValue::hlbool,
231166
value: Some(hlbool.as_union_value()),
@@ -236,10 +171,10 @@ impl TryFrom<FunctionCall> for Vec<u8> {
236171
ParameterValue::String(s) => {
237172
let hlstring = {
238173
let val = builder.create_string(s.as_str());
239-
hlstring::create(&mut builder, &hlstringArgs { value: Some(val) })
174+
hlstring::create(builder, &hlstringArgs { value: Some(val) })
240175
};
241176
let parameter = Parameter::create(
242-
&mut builder,
177+
builder,
243178
&ParameterArgs {
244179
value_type: FbParameterValue::hlstring,
245180
value: Some(hlstring.as_union_value()),
@@ -251,13 +186,13 @@ impl TryFrom<FunctionCall> for Vec<u8> {
251186
let vec_bytes = builder.create_vector(v);
252187

253188
let hlvecbytes = hlvecbytes::create(
254-
&mut builder,
189+
builder,
255190
&hlvecbytesArgs {
256191
value: Some(vec_bytes),
257192
},
258193
);
259194
let parameter = Parameter::create(
260-
&mut builder,
195+
builder,
261196
&ParameterArgs {
262197
value_type: FbParameterValue::hlvecbytes,
263198
value: Some(hlvecbytes.as_union_value()),
@@ -279,7 +214,7 @@ impl TryFrom<FunctionCall> for Vec<u8> {
279214
};
280215

281216
let function_call = FbFunctionCall::create(
282-
&mut builder,
217+
builder,
283218
&FbFunctionCallArgs {
284219
function_name: Some(function_name),
285220
parameters,
@@ -288,9 +223,64 @@ impl TryFrom<FunctionCall> for Vec<u8> {
288223
},
289224
);
290225
builder.finish_size_prefixed(function_call, None);
291-
let res = builder.finished_data().to_vec();
226+
builder.finished_data()
227+
}
228+
}
229+
230+
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
231+
pub fn validate_guest_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> {
232+
let guest_function_call_fb = size_prefixed_root::<FbFunctionCall>(function_call_buffer)
233+
.map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
234+
match guest_function_call_fb.function_call_type() {
235+
FbFunctionCallType::guest => Ok(()),
236+
other => {
237+
bail!("Invalid function call type: {:?}", other);
238+
}
239+
}
240+
}
241+
242+
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
243+
pub fn validate_host_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> {
244+
let host_function_call_fb = size_prefixed_root::<FbFunctionCall>(function_call_buffer)
245+
.map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
246+
match host_function_call_fb.function_call_type() {
247+
FbFunctionCallType::host => Ok(()),
248+
other => {
249+
bail!("Invalid function call type: {:?}", other);
250+
}
251+
}
252+
}
253+
254+
impl TryFrom<&[u8]> for FunctionCall {
255+
type Error = Error;
256+
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
257+
fn try_from(value: &[u8]) -> Result<Self> {
258+
let function_call_fb = size_prefixed_root::<FbFunctionCall>(value)
259+
.map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
260+
let function_name = function_call_fb.function_name();
261+
let function_call_type = match function_call_fb.function_call_type() {
262+
FbFunctionCallType::guest => FunctionCallType::Guest,
263+
FbFunctionCallType::host => FunctionCallType::Host,
264+
other => {
265+
bail!("Invalid function call type: {:?}", other);
266+
}
267+
};
268+
let expected_return_type = function_call_fb.expected_return_type().try_into()?;
269+
let parameters = function_call_fb
270+
.parameters()
271+
.map(|v| {
272+
v.iter()
273+
.map(|p| p.try_into())
274+
.collect::<Result<Vec<ParameterValue>>>()
275+
})
276+
.transpose()?;
292277

293-
Ok(res)
278+
Ok(Self {
279+
function_name: function_name.to_string(),
280+
parameters,
281+
function_call_type,
282+
expected_return_type,
283+
})
294284
}
295285
}
296286

@@ -303,7 +293,8 @@ mod tests {
303293

304294
#[test]
305295
fn read_from_flatbuffer() -> Result<()> {
306-
let test_data: Vec<u8> = FunctionCall::new(
296+
let mut builder = FlatBufferBuilder::new();
297+
let test_data = FunctionCall::new(
307298
"PrintTwelveArgs".to_string(),
308299
Some(vec![
309300
ParameterValue::String("1".to_string()),
@@ -322,10 +313,9 @@ mod tests {
322313
FunctionCallType::Guest,
323314
ReturnType::Int,
324315
)
325-
.try_into()
326-
.unwrap();
316+
.encode(&mut builder);
327317

328-
let function_call = FunctionCall::try_from(test_data.as_slice())?;
318+
let function_call = FunctionCall::try_from(test_data)?;
329319
assert_eq!(function_call.function_name, "PrintTwelveArgs");
330320
assert!(function_call.parameters.is_some());
331321
let parameters = function_call.parameters.unwrap();

src/hyperlight_guest/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ buddy_system_allocator = "0.11.0"
2424
hyperlight-common = { workspace = true }
2525
spin = "0.10.0"
2626
log = { version = "0.4", default-features = false }
27+
flatbuffers = { version= "25.2.10", default-features = false }
2728

2829
[build-dependencies]
2930
cc = "1.2"

src/hyperlight_guest/src/guest_function_call.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ fn internal_dispatch_function() -> Result<()> {
9393
set_error(e.kind.clone(), e.message.as_str());
9494
})?;
9595

96-
push_shared_output_data(result_vec)
96+
push_shared_output_data(&result_vec)
9797
}
9898

9999
// This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt()

src/hyperlight_guest/src/host_function_call.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use alloc::format;
1818
use alloc::string::ToString;
1919
use alloc::vec::Vec;
2020
use core::arch::global_asm;
21+
use flatbuffers::FlatBufferBuilder;
2122

2223
use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType};
2324
use hyperlight_common::flatbuffer_wrappers::function_types::{
@@ -73,11 +74,8 @@ pub fn call_host_function(
7374

7475
validate_host_function_call(&host_function_call)?;
7576

76-
let host_function_call_buffer: Vec<u8> = host_function_call
77-
.try_into()
78-
.expect("Unable to serialize host function call");
79-
80-
push_shared_output_data(host_function_call_buffer)?;
77+
let mut builder = FlatBufferBuilder::new();
78+
push_shared_output_data(host_function_call.encode(&mut builder))?;
8179

8280
outb(OutBAction::CallFunction as u16, 0);
8381

src/hyperlight_guest/src/logging.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ fn write_log_data(
4444
.try_into()
4545
.expect("Failed to convert GuestLogData to bytes");
4646

47-
push_shared_output_data(bytes).expect("Unable to push log data to shared output data");
47+
push_shared_output_data(&bytes).expect("Unable to push log data to shared output data");
4848
}
4949

5050
pub fn log_message(

src/hyperlight_guest/src/shared_output_data.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@ limitations under the License.
1616

1717
use alloc::format;
1818
use alloc::string::ToString;
19-
use alloc::vec::Vec;
2019
use core::slice::from_raw_parts_mut;
2120

2221
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
2322

2423
use crate::error::{HyperlightGuestError, Result};
2524
use crate::P_PEB;
2625

27-
pub fn push_shared_output_data(data: Vec<u8>) -> Result<()> {
26+
pub fn push_shared_output_data(data: &[u8]) -> Result<()> {
2827
let peb_ptr = unsafe { P_PEB.unwrap() };
2928
let shared_buffer_size = unsafe { (*peb_ptr).outputdata.outputDataSize as usize };
3029
let odb = unsafe {

0 commit comments

Comments
 (0)