1use crate::host::{with_host, JsObj};
22use fusevm::Value;
23use indexmap::IndexMap;
24
25pub const METHODS: &[&str] = &[
26 "getHeapStatistics",
27 "getHeapSpaceStatistics",
28 "getHeapCodeStatistics",
29 "serialize",
30 "deserialize",
31 "setFlagsFromString",
32 "getHeapSnapshot",
33 "cachedDataVersionTag",
34];
35
36const CACHED_DATA_VERSION_TAG: f64 = 3_527_742_766.0;
42
43pub const SERIALIZER_METHODS: &[&str] = &["writeHeader", "writeValue", "releaseBuffer"];
46
47pub const DESERIALIZER_METHODS: &[&str] = &["readHeader", "readValue"];
49
50pub fn call(method: &str, args: &[Value]) -> Option<Result<Value, String>> {
51 Some(match method {
52 "getHeapStatistics" => Ok(heap_statistics()),
53 "getHeapSpaceStatistics" => Ok(with_host(|h| h.new_array(Vec::new()))),
55 "getHeapCodeStatistics" => Ok(heap_code_statistics()),
56 "serialize" => serialize(args),
57 "deserialize" => deserialize(args),
58 "setFlagsFromString" => Ok(Value::Undef),
60 "getHeapSnapshot" => Err(crate::host::type_error(
61 "v8.getHeapSnapshot is not supported: node-js does not run on V8",
62 )),
63 "cachedDataVersionTag" => Ok(Value::Float(CACHED_DATA_VERSION_TAG)),
64 _ => return None,
65 })
66}
67
68pub fn constant(name: &str) -> Option<Value> {
72 match name {
73 "Serializer" | "Deserializer" | "DefaultSerializer" | "DefaultDeserializer" => {
74 Some(with_host(|h| h.alloc(JsObj::Builtin(name.into()))))
75 }
76 _ => None,
77 }
78}
79
80pub fn construct(name: &str, args: &[Value]) -> Result<Value, String> {
88 match name {
89 "Serializer" | "DefaultSerializer" => Ok(with_host(|h| {
90 let mut m = IndexMap::new();
91 m.insert("@@native".into(), h.new_str("Serializer"));
92 m.insert("@@json".into(), Value::Undef);
93 h.new_object(m)
94 })),
95 "Deserializer" | "DefaultDeserializer" => {
96 let json = with_host(|h| h.str_of(&args.first().cloned().unwrap_or(Value::Undef)));
98 Ok(with_host(|h| {
99 let jv = h.new_str(json);
100 let mut m = IndexMap::new();
101 m.insert("@@native".into(), h.new_str("Deserializer"));
102 m.insert("@@json".into(), jv);
103 h.new_object(m)
104 }))
105 }
106 _ => Err(crate::host::type_error(&format!(
107 "v8.{name} is not a constructor"
108 ))),
109 }
110}
111
112pub fn instance_call(
114 tag: &str,
115 recv: &Value,
116 method: &str,
117 args: Vec<Value>,
118) -> Result<Value, String> {
119 match (tag, method) {
120 ("Serializer", "writeHeader") => Ok(Value::Undef),
122 ("Serializer", "writeValue") => {
123 let json = crate::builtins::call_builtin_function(
124 "JSON.stringify",
125 vec![args.first().cloned().unwrap_or(Value::Undef)],
126 )?;
127 let s = with_host(|h| h.str_of(&json));
128 with_host(|h| {
129 let sv = h.new_str(s);
130 if let Some(JsObj::Object(p)) = h.get_mut(recv) {
131 p.insert("@@json".into(), sv);
132 }
133 });
134 Ok(Value::Bool(true))
135 }
136 ("Serializer", "releaseBuffer") => {
137 let s = with_host(|h| match h.get(recv) {
138 Some(JsObj::Object(p)) => match p.get("@@json") {
139 Some(Value::Undef) | None => String::new(),
140 Some(v) => h.str_of(v),
141 },
142 _ => String::new(),
143 });
144 Ok(super::buffer::from_bytes(s.as_bytes()))
145 }
146 ("Deserializer", "readHeader") => Ok(Value::Undef),
148 ("Deserializer", "readValue") => {
149 let sv = with_host(|h| match h.get(recv) {
150 Some(JsObj::Object(p)) => p.get("@@json").cloned().unwrap_or(Value::Undef),
151 _ => Value::Undef,
152 });
153 crate::builtins::call_builtin_function("JSON.parse", vec![sv])
154 }
155 _ => Err(crate::host::type_error(&format!(
156 "{method} is not a function"
157 ))),
158 }
159}
160
161fn heap_statistics() -> Value {
164 zeros_object(&[
165 "total_heap_size",
166 "total_heap_size_executable",
167 "total_physical_size",
168 "total_available_size",
169 "used_heap_size",
170 "heap_size_limit",
171 "malloced_memory",
172 "peak_malloced_memory",
173 "does_zap_garbage",
174 "number_of_native_contexts",
175 "number_of_detached_contexts",
176 "total_global_handles_size",
177 "used_global_handles_size",
178 "external_memory",
179 ])
180}
181
182fn heap_code_statistics() -> Value {
184 zeros_object(&[
185 "code_and_metadata_size",
186 "bytecode_and_metadata_size",
187 "external_script_source_size",
188 "cpu_profiler_metadata_size",
189 ])
190}
191
192fn zeros_object(keys: &[&str]) -> Value {
194 with_host(|h| {
195 let mut m = IndexMap::new();
196 for k in keys {
197 m.insert((*k).to_string(), Value::Float(0.0));
198 }
199 h.new_object(m)
200 })
201}
202
203fn serialize(args: &[Value]) -> Result<Value, String> {
206 let v = args.first().cloned().unwrap_or(Value::Undef);
207 let json = crate::builtins::call_builtin_function("JSON.stringify", vec![v])?;
208 let s = with_host(|h| h.str_of(&json));
209 let sval = with_host(|h| h.new_str(s));
210 super::buffer::static_call("from", std::slice::from_ref(&sval)).unwrap_or(Ok(Value::Undef))
212}
213
214fn deserialize(args: &[Value]) -> Result<Value, String> {
217 let s = with_host(|h| h.str_of(&args.first().cloned().unwrap_or(Value::Undef)));
219 let sval = with_host(|h| h.new_str(s));
220 crate::builtins::call_builtin_function("JSON.parse", vec![sval])
221}