1use super::*;
4
5pub(crate) const B64_CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7pub(crate) fn bytes_to_base64(bytes: &[u8]) -> String {
9 let mut out = String::new();
10 for chunk in bytes.chunks(3) {
11 let b0 = chunk.first().copied().unwrap_or(0);
12 let b1 = chunk.get(1).copied().unwrap_or(0);
13 let b2 = chunk.get(2).copied().unwrap_or(0);
14 out.push(B64_CHARS[(b0 >> 2) as usize] as char);
15 out.push(B64_CHARS[(((b0 & 0x3) << 4) | (b1 >> 4)) as usize] as char);
16 out.push(if chunk.len() > 1 {
17 B64_CHARS[(((b1 & 0xf) << 2) | (b2 >> 6)) as usize] as char
18 } else {
19 '='
20 });
21 out.push(if chunk.len() > 2 {
22 B64_CHARS[(b2 & 0x3f) as usize] as char
23 } else {
24 '='
25 });
26 }
27 out
28}
29
30pub(crate) fn base64_to_bytes(s: &str) -> Vec<u8> {
33 let mut bits: u32 = 0;
34 let mut nbits = 0u32;
35 let mut out: Vec<u8> = Vec::new();
36 for c in s.bytes() {
37 let v = match c {
38 b'A'..=b'Z' => c - b'A',
39 b'a'..=b'z' => c - b'a' + 26,
40 b'0'..=b'9' => c - b'0' + 52,
41 b'+' | b'-' => 62, b'/' | b'_' => 63, _ => continue,
44 };
45 bits = (bits << 6) | v as u32;
46 nbits += 6;
47 if nbits >= 8 {
48 nbits -= 8;
49 out.push((bits >> nbits) as u8);
50 }
51 }
52 out
53}
54
55pub(crate) fn bytes_to_hex(bytes: &[u8]) -> String {
57 const HEX: &[u8; 16] = b"0123456789abcdef";
58 let mut out = String::with_capacity(bytes.len() * 2);
59 for &b in bytes {
60 out.push(HEX[(b >> 4) as usize] as char);
61 out.push(HEX[(b & 0xf) as usize] as char);
62 }
63 out
64}
65
66pub(crate) fn hex_to_bytes(s: &str) -> Option<Vec<u8>> {
68 let s = s.as_bytes();
69 if !s.len().is_multiple_of(2) {
70 return None;
71 }
72 fn nibble(c: u8) -> Option<u8> {
73 match c {
74 b'0'..=b'9' => Some(c - b'0'),
75 b'a'..=b'f' => Some(c - b'a' + 10),
76 b'A'..=b'F' => Some(c - b'A' + 10),
77 _ => None,
78 }
79 }
80 let mut out = Vec::with_capacity(s.len() / 2);
81 for pair in s.chunks(2) {
82 let hi = nibble(pair[0])?;
83 let lo = nibble(pair[1])?;
84 out.push((hi << 4) | lo);
85 }
86 Some(out)
87}
88
89pub(crate) fn btoa(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
90 let s = arg(a, 0).to_js_string();
91 Ok(Value::str(bytes_to_base64(s.as_bytes())))
92}
93pub(crate) fn atob(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
94 let s = arg(a, 0).to_js_string();
95 let out = base64_to_bytes(&s);
96 Ok(Value::str(
97 alloc::string::String::from_utf8_lossy(&out).into_owned(),
98 ))
99}
100
101pub(crate) fn ta_to_bytes(this: &Value) -> Vec<u8> {
103 if let Value::Object(o) = this {
104 if let ObjKind::Bytes(st) = &o.borrow().kind {
105 return st.to_vec();
106 }
107 if let ObjKind::Array(items) = &o.borrow().kind {
108 return items.iter().map(|v| v.to_number() as i64 as u8).collect();
109 }
110 }
111 Vec::new()
112}
113
114pub(crate) fn ta_to_base64(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
116 Ok(Value::str(bytes_to_base64(&ta_to_bytes(&this))))
117}
118
119pub(crate) fn ta_to_hex(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
121 Ok(Value::str(bytes_to_hex(&ta_to_bytes(&this))))
122}
123
124pub(crate) fn ta_from_base64(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
126 let s = arg(a, 0).to_js_string();
127 Ok(make_uint8array(it, base64_to_bytes(&s)))
128}
129
130pub(crate) fn ta_from_hex(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
132 let s = arg(a, 0).to_js_string();
133 match hex_to_bytes(&s) {
134 Some(bytes) => Ok(make_uint8array(it, bytes)),
135 None => {
136 let err = syntax_error_ctor(
137 it,
138 Value::Undefined,
139 &[Value::str("Uint8Array.fromHex: invalid hex string")],
140 )?;
141 Err(err)
142 }
143 }
144}
145
146pub(crate) fn ta_write_bytes_into(this: &Value, bytes: &[u8], consumed_len: usize) -> Value {
153 let mut written = 0usize;
154 if let Value::Object(o) = this {
155 if let ObjKind::Bytes(st) = &o.borrow().kind {
156 written = bytes.len().min(st.len);
157 for (i, byte) in bytes.iter().take(written).enumerate() {
158 st.set(i, *byte as f64);
159 }
160 }
161 let mut b = o.borrow_mut();
162 if let ObjKind::Array(items) = &mut b.kind {
163 let cap = items.len();
164 written = bytes.len().min(cap);
165 for (slot, byte) in items.iter_mut().zip(bytes.iter()).take(written) {
166 *slot = Value::Number(*byte as f64);
167 }
168 }
169 }
170 let read = if written < bytes.len() {
171 consumed_len * written / bytes.len().max(1)
173 } else {
174 consumed_len
175 };
176 let o = Obj::plain();
177 {
178 let mut ob = o.borrow_mut();
179 ob.props.insert("read".into(), Value::Number(read as f64));
180 ob.props.insert("written".into(), Value::Number(written as f64));
181 }
182 Value::Object(o)
183}
184
185pub(crate) fn ta_set_from_base64(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
187 let s = arg(a, 0).to_js_string();
188 let bytes = base64_to_bytes(&s);
189 Ok(ta_write_bytes_into(&this, &bytes, s.chars().count()))
190}
191
192pub(crate) fn ta_set_from_hex(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
194 let s = arg(a, 0).to_js_string();
195 match hex_to_bytes(&s) {
196 Some(bytes) => {
197 let len = s.chars().count();
198 Ok(ta_write_bytes_into(&this, &bytes, len))
199 }
200 None => {
201 let err = syntax_error_ctor(
202 it,
203 Value::Undefined,
204 &[Value::str("Uint8Array.setFromHex: invalid hex string")],
205 )?;
206 Err(err)
207 }
208 }
209}
210
211pub(crate) fn percent_decode(s: &str, plus_as_space: bool) -> String {
217 let bytes = s.as_bytes();
218 let mut out: Vec<u8> = Vec::with_capacity(bytes.len());
219 let mut i = 0;
220 while i < bytes.len() {
221 if bytes[i] == b'%' && i + 2 < bytes.len() {
222 let h1 = bytes[i + 1];
223 let h2 = bytes[i + 2];
224 if let (Some(n1), Some(n2)) = (char::from(h1).to_digit(16), char::from(h2).to_digit(16)) {
225 let byte = ((n1 << 4) | n2) as u8;
226 out.push(byte);
227 i += 3;
228 continue;
229 }
230 }
231 if plus_as_space && bytes[i] == b'+' {
232 out.push(b' ');
233 } else {
234 out.push(bytes[i]);
235 }
236 i += 1;
237 }
238 String::from_utf8(out).unwrap_or_else(|e| String::from_utf8_lossy(e.as_bytes()).into_owned())
239}
240
241pub(crate) fn percent_encode_component(s: &str) -> String {
243 let mut out = String::new();
244 for b in s.as_bytes() {
245 match *b {
246 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'!' | b'~' | b'*'
247 | b'\'' | b'(' | b')' => {
248 out.push(*b as char);
249 }
250 _ => out.push_str(&alloc::format!("%{:02X}", b)),
251 }
252 }
253 out
254}
255
256pub(crate) fn percent_encode_uri(s: &str) -> String {
259 let mut out = String::new();
260 for b in s.as_bytes() {
261 match *b {
262 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'!' | b'~' | b'*'
263 | b'\'' | b'(' | b')' | b';' | b'/' | b'?' | b':' | b'@' | b'&' | b'=' | b'+'
264 | b'$' | b',' | b'#' => {
265 out.push(*b as char);
266 }
267 _ => out.push_str(&alloc::format!("%{:02X}", b)),
268 }
269 }
270 out
271}
272
273pub(crate) fn js_encode_uri_component(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
274 Ok(Value::str(percent_encode_component(&arg(a, 0).to_js_string())))
275}
276pub(crate) fn js_decode_uri_component(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
277 Ok(Value::str(percent_decode(&arg(a, 0).to_js_string(), false)))
278}
279pub(crate) fn js_encode_uri(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
280 Ok(Value::str(percent_encode_uri(&arg(a, 0).to_js_string())))
281}
282pub(crate) fn js_decode_uri(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
283 Ok(Value::str(percent_decode(&arg(a, 0).to_js_string(), false)))
284}
285
286pub(crate) fn js_escape(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
292 let s = arg(a, 0).to_js_string();
293 let mut out = String::new();
294 for c in s.chars() {
295 let unreserved =
296 matches!(c, 'A'..='Z' | 'a'..='z' | '0'..='9' | '@' | '*' | '_' | '+' | '-' | '.' | '/');
297 if unreserved {
298 out.push(c);
299 } else {
300 let cp = c as u32;
301 if cp <= 0xFF {
302 out.push_str(&alloc::format!("%{:02X}", cp));
303 } else {
304 out.push_str(&alloc::format!("%u{:04X}", cp));
305 }
306 }
307 }
308 Ok(Value::str(out))
309}
310pub(crate) fn js_unescape(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
313 let s = arg(a, 0).to_js_string();
314 let chars: Vec<char> = s.chars().collect();
315 let mut out = String::new();
316 let mut i = 0;
317 while i < chars.len() {
318 if chars[i] == '%' && i + 6 <= chars.len() && chars[i + 1] == 'u' {
319 let hex: String = chars[i + 2..i + 6].iter().collect();
320 if let Some(ch) = u32::from_str_radix(&hex, 16).ok().and_then(char::from_u32) {
321 out.push(ch);
322 i += 6;
323 continue;
324 }
325 }
326 if chars[i] == '%' && i + 3 <= chars.len() {
327 let hex: String = chars[i + 1..i + 3].iter().collect();
328 if let Some(ch) = u32::from_str_radix(&hex, 16).ok().and_then(char::from_u32) {
329 out.push(ch);
330 i += 3;
331 continue;
332 }
333 }
334 out.push(chars[i]);
335 i += 1;
336 }
337 Ok(Value::str(out))
338}
339
340pub(crate) static PERF_TS: AtomicU64 = AtomicU64::new(0);
341pub fn next_perf_timestamp() -> f64 {
344 PERF_TS.fetch_add(1, Ordering::Relaxed) as f64
345}
346pub(crate) fn performance_now(_it: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
347 Ok(Value::Number(next_perf_timestamp()))
348}
349pub(crate) fn perf_entries(this: &Value) -> alloc::vec::Vec<Value> {
350 if let Value::Object(o) = this {
351 if let Some(Value::Object(arr)) = o.borrow().props.get("_entries") {
352 if let ObjKind::Array(items) = &arr.borrow().kind {
353 return items.clone();
354 }
355 }
356 }
357 alloc::vec::Vec::new()
358}
359pub(crate) fn perf_push_entry(this: &Value, entry: Value) {
360 if let Value::Object(o) = this {
361 let arr = o.borrow().props.get("_entries").cloned();
362 if let Some(Value::Object(a)) = arr {
363 if let ObjKind::Array(items) = &mut a.borrow_mut().kind {
364 items.push(entry);
365 }
366 }
367 }
368}
369pub(crate) fn make_perf_entry(name: &str, entry_type: &str, start_time: f64, duration: f64) -> Value {
370 let o = Obj::plain();
371 {
372 let mut b = o.borrow_mut();
373 b.props.insert("name".into(), Value::str(name));
374 b.props.insert("entryType".into(), Value::str(entry_type));
375 b.props.insert("startTime".into(), Value::Number(start_time));
376 b.props.insert("duration".into(), Value::Number(duration));
377 }
378 Value::Object(o)
379}
380pub(crate) fn perf_mark(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
383 let name = arg(a, 0).to_js_string();
384 let start = next_perf_timestamp();
385 let entry = make_perf_entry(&name, "mark", start, 0.0);
386 perf_push_entry(&this, entry.clone());
387 perf_notify_observers(it, &this, &entry);
388 Ok(entry)
389}
390pub(crate) fn perf_find_mark_time(this: &Value, name: &str) -> Option<f64> {
391 perf_entries(this).into_iter().rev().find_map(|e| {
392 if let Value::Object(o) = &e {
393 let b = o.borrow();
394 let is_mark = b.props.get("entryType").map(|v| v.to_js_string()) == Some(String::from("mark"));
395 let matches_name = b.props.get("name").map(|v| v.to_js_string()) == Some(String::from(name));
396 if is_mark && matches_name {
397 return b.props.get("startTime").map(|v| v.to_number());
398 }
399 }
400 None
401 })
402}
403pub(crate) fn perf_measure(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
407 let name = arg(a, 0).to_js_string();
408 let start_time = match arg(a, 1) {
409 Value::Undefined => 0.0,
410 v => perf_find_mark_time(&this, &v.to_js_string()).unwrap_or(0.0),
411 };
412 let end_time = match arg(a, 2) {
413 Value::Undefined => next_perf_timestamp(),
414 v => perf_find_mark_time(&this, &v.to_js_string()).unwrap_or_else(next_perf_timestamp),
415 };
416 let entry = make_perf_entry(&name, "measure", start_time, end_time - start_time);
417 perf_push_entry(&this, entry.clone());
418 perf_notify_observers(it, &this, &entry);
419 Ok(entry)
420}
421pub(crate) fn perf_notify_observers(it: &mut Interp, this: &Value, entry: &Value) {
426 let entry_type = if let Value::Object(o) = entry {
427 o.borrow().props.get("entryType").map(|v| v.to_js_string()).unwrap_or_default()
428 } else {
429 return;
430 };
431 let observers: Vec<Value> = if let Value::Object(o) = this {
432 match o.borrow().props.get("_observers") {
433 Some(Value::Object(arr)) => match &arr.borrow().kind {
434 ObjKind::Array(items) => items.clone(),
435 _ => Vec::new(),
436 },
437 _ => Vec::new(),
438 }
439 } else {
440 Vec::new()
441 };
442 for obs in observers {
443 let matches_type = if let Value::Object(o) = &obs {
444 match o.borrow().props.get("_entry_types") {
445 Some(Value::Object(arr)) => match &arr.borrow().kind {
446 ObjKind::Array(items) => items.iter().any(|t| t.to_js_string() == entry_type),
447 _ => false,
448 },
449 _ => false,
450 }
451 } else {
452 false
453 };
454 if !matches_type {
455 continue;
456 }
457 let callback = if let Value::Object(o) = &obs {
458 o.borrow().props.get("_callback").cloned()
459 } else {
460 None
461 };
462 if let Some(cb) = callback.and_then(callable_or_none) {
463 let list = Obj::plain();
464 {
465 let mut b = list.borrow_mut();
466 b.props
467 .insert("_entries".into(), Value::Object(Obj::array(alloc::vec![entry.clone()])));
468 b.props
469 .insert("getEntries".into(), nv("getEntries", perf_observer_list_get_entries));
470 }
471 it.call_listener(
472 &cb,
473 Value::Undefined,
474 &[Value::Object(list), obs.clone()],
475 "PerformanceObserver callback",
476 );
477 }
478 }
479}
480pub(crate) fn perf_observer_list_get_entries(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
481 if let Value::Object(o) = &this {
482 if let Some(v) = o.borrow().props.get("_entries").cloned() {
483 return Ok(v);
484 }
485 }
486 Ok(Value::Object(Obj::array(alloc::vec::Vec::new())))
487}
488pub(crate) fn performance_observer_ctor(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
490 let callback = arg(a, 0);
491 let o = Obj::plain();
492 {
493 let mut b = o.borrow_mut();
494 b.props.insert("_callback".into(), callback);
495 b.props
496 .insert("_entry_types".into(), Value::Object(Obj::array(alloc::vec::Vec::new())));
497 b.props.insert("observe".into(), nv("observe", performance_observer_observe));
498 b.props
499 .insert("disconnect".into(), nv("disconnect", performance_observer_disconnect));
500 b.props.insert(
501 "takeRecords".into(),
502 nv("takeRecords", |_: &mut Interp, _: Value, _: &[Value]| {
503 Ok(Value::Object(Obj::array(alloc::vec::Vec::new())))
504 }),
505 );
506 }
507 Ok(Value::Object(o))
508}
509pub(crate) fn performance_observer_observe(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
521 let opts = arg(a, 0);
522 let types: Vec<Value> = match obj_prop(&opts, "entryTypes") {
523 Some(Value::Object(arr)) => match &arr.borrow().kind {
524 ObjKind::Array(items) => items.clone(),
525 _ => Vec::new(),
526 },
527 _ => match obj_prop(&opts, "type") {
528 Some(t) => alloc::vec![t],
529 None => Vec::new(),
530 },
531 };
532 let buffered = obj_prop(&opts, "buffered").map(|v| v.truthy()).unwrap_or(false);
533 if let Value::Object(o) = &this {
534 o.borrow_mut()
535 .props
536 .insert("_entry_types".into(), Value::Object(Obj::array(types.clone())));
537 }
538 let performance = it.global.borrow().vars.get("performance").cloned();
539 if let Some(Value::Object(perf)) = &performance {
540 let arr = perf.borrow().props.get("_observers").cloned();
541 if let Some(Value::Object(a2)) = arr {
542 if let ObjKind::Array(items) = &mut a2.borrow_mut().kind {
543 let dup = items.iter().any(|v| match (v, &this) {
544 (Value::Object(x), Value::Object(y)) => Rc::ptr_eq(x, y),
545 _ => false,
546 });
547 if !dup {
548 items.push(this.clone());
549 }
550 }
551 }
552 }
553 if buffered {
554 if let Some(perf_val) = performance {
555 let want: Vec<String> = types.iter().map(|t| t.to_js_string()).collect();
556 let matching: Vec<Value> = perf_entries(&perf_val)
557 .into_iter()
558 .filter(|e| {
559 if let Value::Object(o) = e {
560 let et = o.borrow().props.get("entryType").map(|v| v.to_js_string()).unwrap_or_default();
561 want.iter().any(|w| w == &et)
562 } else {
563 false
564 }
565 })
566 .collect();
567 if !matching.is_empty() {
568 let callback = if let Value::Object(o) = &this {
569 o.borrow().props.get("_callback").cloned()
570 } else {
571 None
572 };
573 if let Some(cb) = callback.and_then(callable_or_none) {
574 let list = Obj::plain();
575 {
576 let mut b = list.borrow_mut();
577 b.props.insert("_entries".into(), Value::Object(Obj::array(matching)));
578 b.props
579 .insert("getEntries".into(), nv("getEntries", perf_observer_list_get_entries));
580 }
581 it.call_listener(
582 &cb,
583 Value::Undefined,
584 &[Value::Object(list), this.clone()],
585 "PerformanceObserver callback",
586 );
587 }
588 }
589 }
590 }
591 Ok(Value::Undefined)
592}
593pub(crate) fn performance_observer_disconnect(it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
595 let performance = it.global.borrow().vars.get("performance").cloned();
596 if let Some(Value::Object(perf)) = performance {
597 let arr = perf.borrow().props.get("_observers").cloned();
598 if let Some(Value::Object(a2)) = arr {
599 if let ObjKind::Array(items) = &mut a2.borrow_mut().kind {
600 items.retain(|v| match (v, &this) {
601 (Value::Object(x), Value::Object(y)) => !Rc::ptr_eq(x, y),
602 _ => true,
603 });
604 }
605 }
606 }
607 Ok(Value::Undefined)
608}
609pub(crate) fn perf_get_entries(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
610 Ok(Value::Object(Obj::array(perf_entries(&this))))
611}
612pub(crate) fn perf_get_entries_by_type(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
613 let t = arg(a, 0).to_js_string();
614 let items: alloc::vec::Vec<Value> = perf_entries(&this)
615 .into_iter()
616 .filter(|e| {
617 matches!(e, Value::Object(o) if o.borrow().props.get("entryType").map(|v| v.to_js_string()) == Some(t.clone()))
618 })
619 .collect();
620 Ok(Value::Object(Obj::array(items)))
621}
622pub(crate) fn perf_get_entries_by_name(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
623 let name = arg(a, 0).to_js_string();
624 let type_filter = match arg(a, 1) {
625 Value::Undefined => None,
626 v => Some(v.to_js_string()),
627 };
628 let items: alloc::vec::Vec<Value> = perf_entries(&this)
629 .into_iter()
630 .filter(|e| {
631 if let Value::Object(o) = e {
632 let b = o.borrow();
633 let name_matches = b.props.get("name").map(|v| v.to_js_string()) == Some(name.clone());
634 let type_matches = type_filter
635 .as_ref()
636 .map(|t| b.props.get("entryType").map(|v| v.to_js_string()) == Some(t.clone()))
637 .unwrap_or(true);
638 name_matches && type_matches
639 } else {
640 false
641 }
642 })
643 .collect();
644 Ok(Value::Object(Obj::array(items)))
645}
646pub(crate) fn perf_clear_by_type(this: &Value, entry_type: &str, name_filter: Value) {
647 if let Value::Object(o) = this {
648 let arr = o.borrow().props.get("_entries").cloned();
649 if let Some(Value::Object(a)) = arr {
650 let name_filter = match name_filter {
651 Value::Undefined => None,
652 v => Some(v.to_js_string()),
653 };
654 if let ObjKind::Array(items) = &mut a.borrow_mut().kind {
655 items.retain(|e| {
656 if let Value::Object(eo) = e {
657 let b = eo.borrow();
658 let is_type =
659 b.props.get("entryType").map(|v| v.to_js_string()) == Some(String::from(entry_type));
660 let name_ok = name_filter
661 .as_ref()
662 .map(|n| b.props.get("name").map(|v| v.to_js_string()) == Some(n.clone()))
663 .unwrap_or(true);
664 !(is_type && name_ok)
665 } else {
666 true
667 }
668 });
669 }
670 }
671 }
672}
673pub(crate) fn perf_clear_marks(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
674 perf_clear_by_type(&this, "mark", arg(a, 0));
675 Ok(Value::Undefined)
676}
677pub(crate) fn perf_clear_measures(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
678 perf_clear_by_type(&this, "measure", arg(a, 0));
679 Ok(Value::Undefined)
680}
681
682pub(crate) fn next_rand_u64() -> u64 {
684 let mut x = RNG_SEED.load(Ordering::Relaxed);
685 x ^= x >> 12;
686 x ^= x << 25;
687 x ^= x >> 27;
688 RNG_SEED.store(x, Ordering::Relaxed);
689 x.wrapping_mul(0x2545F4914F6CDD1D)
690}
691