File Coverage

blib/lib/Wasm/Wasmtime/Func.pm
Criterion Covered Total %
statement 52 52 100.0
branch 4 4 100.0
condition n/a
subroutine 19 19 100.0
pod 1 1 100.0
total 76 76 100.0


line stmt bran cond sub pod time code
1             package Wasm::Wasmtime::Func;
2              
3 16     16   669 use strict;
  16         61  
  16         502  
4 16     16   95 use warnings;
  16         33  
  16         417  
5 16     16   311 use 5.008004;
  16         114  
6 16     16   108 use base qw( Wasm::Wasmtime::Extern );
  16         39  
  16         2275  
7 16     16   125 use Ref::Util qw( is_blessed_ref is_plain_arrayref );
  16         49  
  16         1028  
8 16     16   111 use Wasm::Wasmtime::FFI;
  16         66  
  16         1684  
9 16     16   5754 use Wasm::Wasmtime::FuncType;
  16         63  
  16         570  
10 16     16   5015 use Wasm::Wasmtime::Trap;
  16         46  
  16         587  
11 16     16   103 use FFI::C::Util qw( set_array_count addressof );
  16         35  
  16         1024  
12 16     16   109 use Sub::Install;
  16         31  
  16         183  
13 16     16   467 use Carp ();
  16         50  
  16         359  
14 16     16   89 use constant is_func => 1;
  16         40  
  16         1175  
15 16     16   106 use constant kind => 'func';
  16         63  
  16         2023  
16             use overload
17 1     1   2 '&{}' => sub { my $self = shift; sub { $self->call(@_) } },
  1         6  
  1         5  
18 14     14   1434 bool => sub { 1 },
19 16     16   146 fallback => 1;
  16         52  
  16         206  
20             ;
21              
22             # ABSTRACT: Wasmtime function class
23             our $VERSION = '0.22'; # VERSION
24              
25              
26             $ffi_prefix = 'wasm_func_';
27             $ffi->load_custom_type('::PtrObject' => 'wasm_func_t' => __PACKAGE__);
28              
29              
30             $ffi->attach( [ wasmtime_func_new => 'new' ] => ['wasm_store_t', 'wasm_functype_t', '(opaque,opaque,opaque)->opaque'] => 'wasm_func_t' => sub {
31             my $xsub = shift;
32             my $class = shift;
33             if(is_blessed_ref $_[0] && $_[0]->isa('Wasm::Wasmtime::Store'))
34             {
35             my $store = shift;
36             my($functype, $cb) = is_plain_arrayref($_[0])
37             ? (Wasm::Wasmtime::FuncType->new($_[0], $_[1]), $_[2])
38             : @_;
39              
40             my $param_arity = scalar $functype->params;
41             my $result_arity = scalar$functype->results;
42              
43             require Wasm::Wasmtime::Caller;
44             my $wrapper = $ffi->closure(sub {
45             my($caller, $params, $results) = @_;
46             $caller = Wasm::Wasmtime::Caller->new($caller);
47             unshift @Wasm::Wasmtime::Caller::callers, $caller;
48              
49             my @args = $param_arity ? do {
50             my $args = Wasm::Wasmtime::ValVec->from_c($params);
51             set_array_count($args, $param_arity) unless _v0_23_0();
52             $args->to_perl;
53             } : ();
54              
55             local $@ = '';
56             my @ret = eval {
57             $cb->(@args);
58             };
59             if(my $error = $@)
60             {
61             my $trap = is_blessed_ref $error && $error->isa('Wasm::Wasmtime::Trap')
62             ? $error
63             : Wasm::Wasmtime::Trap->new($store, "$error\0");
64             delete $caller->{ptr};
65             shift @Wasm::Wasmtime::Caller::callers;
66             return delete $trap->{ptr};
67             }
68             else
69             {
70             if($result_arity)
71             {
72             $results = Wasm::Wasmtime::ValVec->from_c($results);
73             my @types = $functype->results;
74             foreach my $i (0..$#types)
75             {
76             my $kind = $types[$i]->kind;
77             my $result = $results->get($i);
78             $result->kind($types[$i]->kind_num);
79             $result->of->$kind(shift @ret);
80             }
81             }
82             delete $caller->{ptr};
83             shift @Wasm::Wasmtime::Caller::callers;
84             return undef;
85             }
86             });
87             my $self = $xsub->($store, $functype, $wrapper);
88             $self->{store} = $store;
89             $self->{wrapper} = $wrapper;
90             return $self;
91             }
92             else
93             {
94             my ($ptr, $owner) = @_;
95             bless {
96             ptr => $ptr,
97             owner => $owner,
98             }, $class;
99             }
100             });
101              
102              
103             if(_v0_23_0())
104             {
105             $ffi->attach( call => ['wasm_func_t', 'record(Wasm::Wasmtime::Vec)*', 'record(Wasm::Wasmtime::Vec)*'] => 'wasm_trap_t' => sub {
106             my $xsub = shift;
107             my $self = shift;
108             my @params = $self->type->params;
109             my $args = Wasm::Wasmtime::ValVec->from_perl(\@_, \@params);
110             my $results = $self->result_arity ? Wasm::Wasmtime::ValVec->new($self->result_arity) : undef;
111              
112             my $args_vec = Wasm::Wasmtime::Vec->new(
113             size => scalar @params,
114             data => defined $args ? addressof($args) : undef,
115             );
116              
117             my $results_vec = Wasm::Wasmtime::Vec->new(
118             size => $self->result_arity,
119             data => defined $results ? addressof($results) : undef,
120             );
121              
122             my $trap = $xsub->($self, $args_vec, $results_vec);
123              
124             die $trap if $trap;
125             return unless defined $results;
126             my @results = $results->to_perl;
127             wantarray ? @results : $results[0]; ## no critic (Community::Wantarray)
128             });
129             }
130             else
131             {
132             $ffi->attach( call => ['wasm_func_t', 'wasm_val_vec_t', 'wasm_val_vec_t'] => 'wasm_trap_t' => sub {
133             my $xsub = shift;
134             my $self = shift;
135             my $args = Wasm::Wasmtime::ValVec->from_perl(\@_, [$self->type->params]);
136             my $results = $self->result_arity ? Wasm::Wasmtime::ValVec->new($self->result_arity) : undef;
137              
138             my $trap = $xsub->($self, $args, $results);
139              
140             die $trap if $trap;
141             return unless defined $results;
142             my @results = $results->to_perl;
143             wantarray ? @results : $results[0]; ## no critic (Community::Wantarray)
144             });
145             }
146              
147              
148             sub attach
149             {
150 30     30 1 1249 my $self = shift;
151 30 100       90 my $package = @_ == 2 ? shift : caller;
152 30         55 my $name = shift;
153 30 100       360 if($package->can($name))
154             {
155 1         208 Carp::carp("attaching ${package}::$name replaces existing subroutine");
156             }
157             Sub::Install::reinstall_sub({
158 32     32   20819 code => sub { $self->call(@_) },
        30      
159 30         371 into => $package,
160             as => $name,
161             });
162             }
163              
164              
165             $ffi->attach( type => ['wasm_func_t'] => 'wasm_functype_t' => sub {
166             my($xsub, $self) = @_;
167             my $type = $xsub->($self);
168             $type->{owner} = $self->{owner} || $self;
169             $type;
170             });
171              
172              
173             $ffi->attach( param_arity => ['wasm_func_t'] => 'size_t' => sub {
174             my($xsub, $self) = @_;
175             $xsub->($self);
176             });
177              
178              
179             $ffi->attach( result_arity => ['wasm_func_t'] => 'size_t' => sub {
180             my($xsub, $self) = @_;
181             $xsub->($self);
182             });
183              
184             __PACKAGE__->_cast(0);
185             _generate_destroy();
186              
187             1;
188              
189             __END__