File Coverage

blib/lib/Wasm/Wasmtime/FFI.pm
Criterion Covered Total %
statement 106 107 99.0
branch 18 22 81.8
condition 5 6 83.3
subroutine 27 27 100.0
pod n/a
total 156 162 96.3


line stmt bran cond sub pod time code
1             package Wasm::Wasmtime::FFI;
2              
3 36     36   800444 use strict;
  36         86  
  36         1100  
4 36     36   188 use warnings;
  36         90  
  36         876  
5 36     36   585 use 5.008004;
  36         233  
6 36     36   16704 use FFI::C 0.05;
  36         78137  
  36         1061  
7 36     36   11497 use FFI::C::Util ();
  36         161306  
  36         1106  
8 36     36   18152 use FFI::Platypus 1.26;
  36         201954  
  36         1034  
9 36     36   16746 use FFI::Platypus::Buffer ();
  36         21249  
  36         1085  
10 36     36   16745 use FFI::CheckLib 0.26 qw( find_lib );
  36         259566  
  36         2624  
11 36     36   11160 use Sub::Install;
  36         44397  
  36         225  
12 36     36   16305 use Devel::GlobalDestruction ();
  36         71593  
  36         886  
13 36     36   255 use constant ();
  36         82  
  36         678  
14 36     36   192 use base qw( Exporter );
  36         100  
  36         13009  
15              
16             # ABSTRACT: Private class for Wasm::Wasmtime
17             our $VERSION = '0.22'; # VERSION
18              
19              
20             our @EXPORT = qw( $ffi $ffi_prefix _generate_vec_class _generate_destroy _v0_23_0 );
21              
22             sub _lib
23             {
24 36 50   36   355 return $ENV{WASM_WASMTIME_FFI} if defined $ENV{WASM_WASMTIME_FFI};
25 36         148 my @symbols = (
26             # 0.19.0
27             'wasmtime_func_as_funcref',
28             # 0.20.0 / 0.21.0
29             'wasmtime_module_serialize',
30             'wasmtime_module_deserialize',
31             'wasmtime_store_gc',
32             ## 0.23.0
33             #'wasmtime_config_consume_fuel_set',
34             #'wasmtime_config_max_instances_set
35             );
36 36         164 my $lib = find_lib lib => 'wasmtime', symbol => \@symbols;
37 36 50       295427 return $lib if $lib;
38 36         282 $lib = find_lib lib => 'wasmtime', alien => 'Alien::wasmtime', symbol => \@symbols;
39 36 50       2897146 return $lib if $lib;
40 0         0 die 'unable to find wasmtime 0.19.0 or better';
41             }
42              
43             our $ffi_prefix = 'wasm_';
44             our $ffi = FFI::Platypus->new( api => 1 );
45             FFI::C->ffi($ffi);
46             $ffi->lib(__PACKAGE__->_lib);
47             $ffi->mangler(sub {
48             my $name = shift;
49             return $name if $name =~ /^(wasm|wasmtime|wasi)_/;
50             return $ffi_prefix . $name;
51             });
52              
53             constant->import( _v0_23_0 => $ffi->find_symbol('wasmtime_config_consume_fuel_set') ? 1 : 0);
54              
55             { package Wasm::Wasmtime::Vec;
56 36     36   16960 use FFI::Platypus::Record;
  36         56047  
  36         3428  
57             record_layout_1(
58             $ffi,
59             size_t => 'size',
60             opaque => 'data',
61             );
62             }
63              
64             { package Wasm::Wasmtime::ByteVec;
65 36     36   363 use base qw( Wasm::Wasmtime::Vec );
  36         89  
  36         29502  
66              
67             $ffi->type('record(Wasm::Wasmtime::ByteVec)' => 'wasm_byte_vec_t');
68             $ffi_prefix = 'wasm_byte_vec_';
69              
70             sub new
71             {
72 247     247   564 my $class = shift;
73 247 100       641 if(@_ == 1)
74             {
75 169         581 my($data, $size) = FFI::Platypus::Buffer::scalar_to_buffer($_[0]);
76 169         2131 return $class->SUPER::new(
77             size => $size,
78             data => $data,
79             );
80             }
81             else
82             {
83 78         272 return $class->SUPER::new(@_);
84             }
85             }
86              
87             sub get
88             {
89 303     303   6959 my($self) = @_;
90 303         1502 FFI::Platypus::Buffer::buffer_to_scalar($self->data, $self->size);
91             }
92              
93             $ffi->attach( delete => ['wasm_byte_vec_t*'] => 'void' );
94             }
95              
96             sub _generic_vec_delete
97             {
98 180     180   1124 my($xsub, $self) = @_;
99 180         935 $xsub->($self);
100             # cannot use SUPER::DELETE because we aren't
101             # in the right package.
102 180         503 Wasm::Wasmtime::Vec::DESTROY($self);
103             }
104              
105             sub _generate_vec_class
106             {
107 87     87   295 my %opts = @_;
108 87         275 my($class) = caller;
109 87         204 my $type = $class;
110 87         449 $type =~ s/^.*:://;
111 87         274 my $v_type = "wasm_@{[ lc $type ]}_vec_t";
  87         398  
112 87         297 my $vclass = "Wasm::Wasmtime::${type}Vec";
113 87         174 my $prefix = "wasm_@{[ lc $type ]}_vec";
  87         305  
114              
115             Sub::Install::install_sub({
116             code => sub {
117 334     334   1933 my($self) = @_;
118 334         1139 my $size = $self->size;
119 334 100       1527 return () if $size == 0;
120 218         1404 my $ptrs = $ffi->cast('opaque', "opaque[$size]", $self->data);
121 218         25943 map { $class->new($_, $self) } @$ptrs;
  435         1553  
122             },
123 87         926 into => $vclass,
124             as => 'to_list',
125             });
126              
127             {
128 36     36   328 no strict 'refs';
  36         169  
  36         43363  
  87         6040  
129 87         188 @{join '::', $vclass, 'ISA'} = ('Wasm::Wasmtime::Vec');
  87         2056  
130             }
131 87         486 $ffi_prefix = "${prefix}_";
132 87         586 $ffi->type("record($vclass)" => $v_type);
133             $ffi->attach( [ delete => join('::', $vclass, 'DESTROY') ] => ["$v_type*"] => \&_generic_vec_delete)
134 87 100 66     11246 if !defined($opts{delete}) || $opts{delete};
135              
136             }
137              
138             sub _wrapper_destroy
139             {
140 840     840   107445 my($xsub, $self) = @_;
141 840 50       20249 return if Devel::GlobalDestruction::in_global_destruction();
142 840 100 100     9357 if(defined $self->{ptr} && !defined $self->{owner})
143             {
144 197         859 $xsub->($self);
145 197         5193 delete $self->{ptr};
146             }
147             }
148              
149             sub _generate_destroy
150             {
151 401     401   914 my $caller = caller;
152 401         1051 my $type = lc $caller;
153 401 100       1636 if($type =~ /::linker$/)
    100          
154             {
155 9         26 $type = 'wasmtime_linker_t';
156             }
157             elsif($type =~ /::wasi/)
158             {
159 21         244 $type =~ s/^.*::wasi(.*)$/wasi_${1}_t/g;
160             }
161             else
162             {
163 371         1912 $type =~ s/^.*:://;
164 371         967 $type = "wasm_${type}_t";
165             }
166 401         2206 $ffi->attach( [ delete => join('::', $caller, 'DESTROY') ] => [ $type ] => \&_wrapper_destroy);
167             }
168              
169             { package Wasm::Wasmtime::Error;
170              
171             $ffi_prefix = 'wasmtime_error_';
172             $ffi->custom_type(
173             wasmtime_error_t => {
174             native_type => 'opaque',
175             native_to_perl => sub {
176             defined $_[0] ? __PACKAGE__->new($_[0]) : undef
177             },
178             },
179             );
180              
181             Sub::Install::install_sub({
182             code => sub {
183 8     8   35 my($class, $ptr, $owner) = @_;
184 8         68 bless {
185             ptr => $ptr,
186             owner => $owner,
187             }, $class;
188             },
189             into => __PACKAGE__,
190             as => 'new',
191             });
192              
193             $ffi->attach( message => ['wasmtime_error_t','wasm_byte_vec_t*'] => sub {
194             my($xsub, $self) = @_;
195             my $message = Wasm::Wasmtime::ByteVec->new;
196             $xsub->($self->{ptr}, $message);
197             my $ret = $message->get;
198             $message->delete;
199             $ret;
200             });
201              
202             $ffi->attach( [ delete => "DESTROY" ] => ['wasmtime_error_t'] => sub {
203             my($xsub, $self) = @_;
204             if(defined $self->{ptr} && !defined $self->{owner})
205             {
206             $xsub->($self->{ptr});
207             }
208             });
209             }
210              
211             { package Wasm::Wasmtime::Val::Of;
212             FFI::C->union(of_t => [
213             i32 => 'sint32',
214             i64 => 'sint64',
215             f32 => 'float',
216             f64 => 'double',
217             anyref => 'opaque',
218             funcref => 'opaque',
219             ]);
220             }
221              
222             my %kind = (
223             0 => 'i32',
224             1 => 'i64',
225             2 => 'f32',
226             3 => 'f64',
227             128 => 'anyref',
228             129 => 'funcref',
229             );
230              
231             { package Wasm::Wasmtime::Val;
232             FFI::C->struct(wasm_val_t => [
233             kind => 'uint8',
234             of => 'of_t',
235             ]);
236              
237             sub to_perl
238             {
239 59     59   109 my $self = shift;
240 59         177 my $kind = $kind{$self->kind};
241 59         787 $self->of->$kind;
242             }
243             }
244              
245             { package Wasm::Wasmtime::ValVec;
246             FFI::C->array(wasm_val_vec_t => [
247             'wasm_val_t',
248             ], { nullable => 1 });
249              
250             sub to_perl
251             {
252 38     38   73 my $self = shift;
253 38         130 map { $_->to_perl } @$self
  48         2353  
254             }
255              
256             if(Wasm::Wasmtime::FFI::_v0_23_0())
257             {
258             {
259             package Wasm::Wasmtime::ValVecWrapper;
260             FFI::C->struct(wasm_val_vec_wrapper_t => [
261             size => 'size_t',
262             data => 'opaque',
263             ]);
264              
265             }
266              
267             $ffi->attach_cast('from_c', 'opaque', 'wasm_val_vec_wrapper_t', sub {
268             my($xsub, undef, $ptr) = @_;
269             my $wrapper = $xsub->($ptr);
270             my $inner = $ffi->cast('opaque', 'wasm_val_vec_t', $wrapper->data);
271             FFI::C::Util::set_array_count($inner, $wrapper->size);
272             return $inner;
273             });
274             }
275             else
276             {
277             $ffi->attach_cast('from_c', 'opaque', 'wasm_val_vec_t', sub {
278             my($xsub, undef, $ptr) = @_;
279             $xsub->($ptr);
280             });
281             }
282              
283             sub from_perl
284             {
285 53     53   148 my($class, $vals, $types) = @_;
286 53 100       182 @$vals ? $class->new([map { { kind => $_->kind_num, of => { $_->kind => shift @$vals } } } @$types]) : undef;
  70         637  
287             }
288             }
289              
290             1;
291              
292             __END__