@@ -15,12 +15,14 @@ use crate::{
15
15
droppable_value:: DroppableValue ,
16
16
ContextError , ExecutionError , JsValue , ValueError ,
17
17
} ;
18
+ use libquickjs_sys:: JS_DupValue ;
18
19
19
20
// JS_TAG_* constants from quickjs.
20
21
// For some reason bindgen does not pick them up.
21
22
#[ cfg( feature = "bigint" ) ]
22
23
const TAG_BIG_INT : i64 = -10 ;
23
24
const TAG_STRING : i64 = -7 ;
25
+ const TAG_FUNCTION_BYTECODE : i64 = -2 ;
24
26
const TAG_OBJECT : i64 = -1 ;
25
27
const TAG_INT : i64 = 0 ;
26
28
const TAG_BOOL : i64 = 1 ;
@@ -29,23 +31,6 @@ const TAG_UNDEFINED: i64 = 3;
29
31
const TAG_EXCEPTION : i64 = 6 ;
30
32
const TAG_FLOAT64 : i64 = 7 ;
31
33
32
- /// Free a JSValue.
33
- /// This function is the equivalent of JS_FreeValue from quickjs, which can not
34
- /// be used due to being `static inline`.
35
- unsafe fn free_value ( context : * mut q:: JSContext , value : q:: JSValue ) {
36
- // All tags < 0 are garbage collected and need to be freed.
37
- if value. tag < 0 {
38
- // This transmute is OK since if tag < 0, the union will be a refcount
39
- // pointer.
40
- let ptr = value. u . ptr as * mut q:: JSRefCountHeader ;
41
- let pref: & mut q:: JSRefCountHeader = & mut * ptr;
42
- pref. ref_count -= 1 ;
43
- if pref. ref_count <= 0 {
44
- q:: __JS_FreeValue ( context, value) ;
45
- }
46
- }
47
- }
48
-
49
34
#[ cfg( feature = "chrono" ) ]
50
35
fn js_date_constructor ( context : * mut q:: JSContext ) -> q:: JSValue {
51
36
let global = unsafe { q:: JS_GetGlobalObject ( context) } ;
@@ -61,7 +46,7 @@ fn js_date_constructor(context: *mut q::JSContext) -> q::JSValue {
61
46
)
62
47
} ;
63
48
assert_eq ! ( date_constructor. tag, TAG_OBJECT ) ;
64
- unsafe { free_value ( context, global) } ;
49
+ unsafe { q :: JS_FreeValue ( context, global) } ;
65
50
date_constructor
66
51
}
67
52
@@ -80,7 +65,7 @@ fn js_create_bigint_function(context: *mut q::JSContext) -> q::JSValue {
80
65
)
81
66
} ;
82
67
assert_eq ! ( bigint_function. tag, TAG_OBJECT ) ;
83
- unsafe { free_value ( context, global) } ;
68
+ unsafe { q :: JS_FreeValue ( context, global) } ;
84
69
bigint_function
85
70
}
86
71
@@ -137,9 +122,11 @@ fn serialize_value(context: *mut q::JSContext, value: JsValue) -> Result<q::JSVa
137
122
Err ( e) => {
138
123
// Make sure to free the array if a individual element
139
124
// fails.
125
+
140
126
unsafe {
141
- free_value ( context, arr) ;
127
+ q :: JS_FreeValue ( context, arr) ;
142
128
}
129
+
143
130
return Err ( e) ;
144
131
}
145
132
} ;
@@ -157,7 +144,7 @@ fn serialize_value(context: *mut q::JSContext, value: JsValue) -> Result<q::JSVa
157
144
// Make sure to free the array if a individual
158
145
// element fails.
159
146
unsafe {
160
- free_value ( context, arr) ;
147
+ q :: JS_FreeValue ( context, arr) ;
161
148
}
162
149
return Err ( ValueError :: Internal (
163
150
"Could not append element to array" . into ( ) ,
@@ -178,7 +165,7 @@ fn serialize_value(context: *mut q::JSContext, value: JsValue) -> Result<q::JSVa
178
165
let qvalue = serialize_value ( context, value) . map_err ( |e| {
179
166
// Free the object if a property failed.
180
167
unsafe {
181
- free_value ( context, obj) ;
168
+ q :: JS_FreeValue ( context, obj) ;
182
169
}
183
170
e
184
171
} ) ?;
@@ -195,7 +182,7 @@ fn serialize_value(context: *mut q::JSContext, value: JsValue) -> Result<q::JSVa
195
182
if ret < 0 {
196
183
// Free the object if a property failed.
197
184
unsafe {
198
- free_value ( context, obj) ;
185
+ q :: JS_FreeValue ( context, obj) ;
199
186
}
200
187
return Err ( ValueError :: Internal (
201
188
"Could not add add property to object" . into ( ) ,
@@ -227,7 +214,7 @@ fn serialize_value(context: *mut q::JSContext, value: JsValue) -> Result<q::JSVa
227
214
)
228
215
} ;
229
216
unsafe {
230
- free_value ( context, date_constructor) ;
217
+ q :: JS_FreeValue ( context, date_constructor) ;
231
218
}
232
219
233
220
if value. tag != TAG_OBJECT {
@@ -250,7 +237,7 @@ fn serialize_value(context: *mut q::JSContext, value: JsValue) -> Result<q::JSVa
250
237
)
251
238
} ;
252
239
let s = DroppableValue :: new ( s, |& mut s| unsafe {
253
- free_value ( context, s) ;
240
+ q :: JS_FreeValue ( context, s) ;
254
241
} ) ;
255
242
if ( * s) . tag != TAG_STRING {
256
243
return Err ( ValueError :: Internal (
@@ -263,7 +250,7 @@ fn serialize_value(context: *mut q::JSContext, value: JsValue) -> Result<q::JSVa
263
250
let bigint_function = js_create_bigint_function ( context) ;
264
251
let bigint_function =
265
252
DroppableValue :: new ( bigint_function, |& mut bigint_function| unsafe {
266
- free_value ( context, bigint_function) ;
253
+ q :: JS_FreeValue ( context, bigint_function) ;
267
254
} ) ;
268
255
let js_bigint = unsafe {
269
256
q:: JS_Call (
@@ -300,7 +287,7 @@ fn deserialize_array(
300
287
let len_raw = unsafe { q:: JS_GetPropertyStr ( context, * raw_value, length_name. as_ptr ( ) ) } ;
301
288
302
289
let len_res = deserialize_value ( context, & len_raw) ;
303
- unsafe { free_value ( context, len_raw) } ;
290
+ unsafe { q :: JS_FreeValue ( context, len_raw) } ;
304
291
let len = match len_res? {
305
292
JsValue :: Int ( x) => x,
306
293
_ => {
@@ -317,7 +304,7 @@ fn deserialize_array(
317
304
return Err ( ValueError :: Internal ( "Could not build array" . into ( ) ) ) ;
318
305
}
319
306
let value_res = deserialize_value ( context, & value_raw) ;
320
- unsafe { free_value ( context, value_raw) } ;
307
+ unsafe { q :: JS_FreeValue ( context, value_raw) } ;
321
308
322
309
let value = value_res?;
323
310
values. push ( value) ;
@@ -364,7 +351,7 @@ fn deserialize_object(context: *mut q::JSContext, obj: &q::JSValue) -> Result<Js
364
351
365
352
let value_res = deserialize_value ( context, & raw_value) ;
366
353
unsafe {
367
- free_value ( context, raw_value) ;
354
+ q :: JS_FreeValue ( context, raw_value) ;
368
355
}
369
356
let value = value_res?;
370
357
@@ -377,7 +364,7 @@ fn deserialize_object(context: *mut q::JSContext, obj: &q::JSValue) -> Result<Js
377
364
378
365
let key_res = deserialize_value ( context, & key_value) ;
379
366
unsafe {
380
- free_value ( context, key_value) ;
367
+ q :: JS_FreeValue ( context, key_value) ;
381
368
}
382
369
let key = match key_res? {
383
370
JsValue :: String ( s) => s,
@@ -469,8 +456,8 @@ fn deserialize_value(
469
456
unsafe { q:: JS_Call ( context, getter, * r, 0 , std:: ptr:: null_mut ( ) ) } ;
470
457
471
458
unsafe {
472
- free_value ( context, getter) ;
473
- free_value ( context, date_constructor) ;
459
+ q :: JS_FreeValue ( context, getter) ;
460
+ q :: JS_FreeValue ( context, date_constructor) ;
474
461
} ;
475
462
476
463
let res = if timestamp_raw. tag == TAG_FLOAT64 {
@@ -488,7 +475,7 @@ fn deserialize_value(
488
475
} ;
489
476
return res;
490
477
} else {
491
- unsafe { free_value ( context, date_constructor) } ;
478
+ unsafe { q :: JS_FreeValue ( context, date_constructor) } ;
492
479
}
493
480
}
494
481
@@ -597,11 +584,17 @@ pub struct OwnedValueRef<'a> {
597
584
impl < ' a > Drop for OwnedValueRef < ' a > {
598
585
fn drop ( & mut self ) {
599
586
unsafe {
600
- free_value ( self . context . context , self . value ) ;
587
+ q :: JS_FreeValue ( self . context . context , self . value ) ;
601
588
}
602
589
}
603
590
}
604
591
592
+ impl < ' a > Clone for OwnedValueRef < ' a > {
593
+ fn clone ( & self ) -> Self {
594
+ Self :: new_dup ( self . context , self . value )
595
+ }
596
+ }
597
+
605
598
impl < ' a > std:: fmt:: Debug for OwnedValueRef < ' a > {
606
599
fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
607
600
match self . value . tag {
@@ -613,6 +606,7 @@ impl<'a> std::fmt::Debug for OwnedValueRef<'a> {
613
606
TAG_FLOAT64 => write ! ( f, "Float(?)" ) ,
614
607
TAG_STRING => write ! ( f, "String(?)" ) ,
615
608
TAG_OBJECT => write ! ( f, "Object(?)" ) ,
609
+ TAG_FUNCTION_BYTECODE => write ! ( f, "Bytecode(?)" ) ,
616
610
_ => write ! ( f, "?" ) ,
617
611
}
618
612
}
@@ -622,6 +616,11 @@ impl<'a> OwnedValueRef<'a> {
622
616
pub fn new ( context : & ' a ContextWrapper , value : q:: JSValue ) -> Self {
623
617
Self { context, value }
624
618
}
619
+ pub fn new_dup ( context : & ' a ContextWrapper , value : q:: JSValue ) -> Self {
620
+ let ret = Self :: new ( context, value) ;
621
+ unsafe { JS_DupValue ( ret. context . context , ret. value ) } ;
622
+ ret
623
+ }
625
624
626
625
/// Get the inner JSValue without freeing in drop.
627
626
///
@@ -632,6 +631,18 @@ impl<'a> OwnedValueRef<'a> {
632
631
v
633
632
}
634
633
634
+ /// Get the inner JSValue without increasing ref count
635
+ pub ( crate ) fn as_inner ( & self ) -> & q:: JSValue {
636
+ & self . value
637
+ }
638
+
639
+ /// Get the inner JSValue while increasing ref count, this is handy when you pass a JSValue to a new owner like e.g. setProperty
640
+ #[ allow( dead_code) ]
641
+ pub ( crate ) fn as_inner_dup ( & self ) -> & q:: JSValue {
642
+ unsafe { q:: JS_DupValue ( self . context . context , self . value ) } ;
643
+ & self . value
644
+ }
645
+
635
646
pub fn is_null ( & self ) -> bool {
636
647
self . value . tag == TAG_NULL
637
648
}
@@ -652,6 +663,10 @@ impl<'a> OwnedValueRef<'a> {
652
663
self . value . tag == TAG_STRING
653
664
}
654
665
666
+ pub fn is_compiled_function ( & self ) -> bool {
667
+ self . value . tag == TAG_FUNCTION_BYTECODE
668
+ }
669
+
655
670
pub fn to_string ( & self ) -> Result < String , ExecutionError > {
656
671
let value = if self . is_string ( ) {
657
672
self . to_value ( ) ?
@@ -680,6 +695,19 @@ impl<'a> OwnedValueRef<'a> {
680
695
_ => Err ( ValueError :: UnexpectedType ) ,
681
696
}
682
697
}
698
+
699
+ #[ cfg( test) ]
700
+ pub fn get_ref_count ( & self ) -> i32 {
701
+ if self . value . tag < 0 {
702
+ // This transmute is OK since if tag < 0, the union will be a refcount
703
+ // pointer.
704
+ let ptr = unsafe { self . value . u . ptr as * mut q:: JSRefCountHeader } ;
705
+ let pref: & mut q:: JSRefCountHeader = & mut unsafe { * ptr } ;
706
+ pref. ref_count
707
+ } else {
708
+ -1
709
+ }
710
+ }
683
711
}
684
712
685
713
/// Wraps an object from the quickjs runtime.
@@ -709,7 +737,7 @@ impl<'a> OwnedObjectRef<'a> {
709
737
} ;
710
738
let t = raw. tag ;
711
739
unsafe {
712
- free_value ( self . value . context . context , raw) ;
740
+ q :: JS_FreeValue ( self . value . context . context , raw) ;
713
741
}
714
742
Ok ( t)
715
743
}
@@ -797,7 +825,7 @@ unsafe extern "C" fn native_module_init(
797
825
/// Cleanup of the context happens in drop.
798
826
pub struct ContextWrapper {
799
827
runtime : * mut q:: JSRuntime ,
800
- context : * mut q:: JSContext ,
828
+ pub ( crate ) context : * mut q:: JSContext ,
801
829
/// Stores callback closures and quickjs data pointers.
802
830
/// This array is write-only and only exists to ensure the lifetime of
803
831
/// the closure.
@@ -937,7 +965,7 @@ impl ContextWrapper {
937
965
}
938
966
939
967
/// Get the last exception from the runtime, and if present, convert it to a ExceptionError.
940
- fn get_exception ( & self ) -> Option < ExecutionError > {
968
+ pub ( crate ) fn get_exception ( & self ) -> Option < ExecutionError > {
941
969
let raw = unsafe { q:: JS_GetException ( self . context ) } ;
942
970
let value = OwnedValueRef :: new ( self , raw) ;
943
971
0 commit comments