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 18 18 100.0
pod 1 1 100.0
total 75 75 100.0


line stmt bran cond sub pod time code
1             package Wasm::Wasmtime::Func;
2              
3 16     16   572 use strict;
  16         94  
  16         474  
4 16     16   89 use warnings;
  16         34  
  16         356  
5 16     16   291 use 5.008004;
  16         62  
6 16     16   159 use base qw( Wasm::Wasmtime::Extern );
  16         39  
  16         2199  
7 16     16   107 use Ref::Util qw( is_blessed_ref is_plain_arrayref );
  16         33  
  16         890  
8 16     16   119 use Wasm::Wasmtime::FFI;
  16         54  
  16         1572  
9 16     16   5650 use Wasm::Wasmtime::FuncType;
  16         43  
  16         528  
10 16     16   4715 use Wasm::Wasmtime::Trap;
  16         41  
  16         545  
11 16     16   115 use FFI::C::Util qw( set_array_count addressof );
  16         39  
  16         978  
12 16     16   101 use Sub::Install;
  16         33  
  16         170  
13 16     16   456 use Carp ();
  16         54  
  16         368  
14 16     16   88 use constant is_func => 1;
  16         43  
  16         1065  
15 16     16   104 use constant kind => 'func';
  16         30  
  16         2006  
16             use overload
17 1     1   3 '&{}' => sub { my $self = shift; sub { $self->call(@_) } },
  1         6  
  1         5  
18 14     14   1189 bool => sub { 1 },
19 16     16   116 fallback => 1;
  16         34  
  16         187  
20             ;
21              
22             # ABSTRACT: Wasmtime function class
23             our $VERSION = '0.23'; # 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             $args->to_perl;
52             } : ();
53              
54             local $@ = '';
55             my @ret = eval {
56             $cb->(@args);
57             };
58             if(my $error = $@)
59             {
60             my $trap = is_blessed_ref $error && $error->isa('Wasm::Wasmtime::Trap')
61             ? $error
62             : Wasm::Wasmtime::Trap->new($store, "$error\0");
63             delete $caller->{ptr};
64             shift @Wasm::Wasmtime::Caller::callers;
65             return delete $trap->{ptr};
66             }
67             else
68             {
69             if($result_arity)
70             {
71             $results = Wasm::Wasmtime::ValVec->from_c($results);
72             my @types = $functype->results;
73             foreach my $i (0..$#types)
74             {
75             my $kind = $types[$i]->kind;
76             my $result = $results->get($i);
77             $result->kind($types[$i]->kind_num);
78             $result->of->$kind(shift @ret);
79             }
80             }
81             delete $caller->{ptr};
82             shift @Wasm::Wasmtime::Caller::callers;
83             return undef;
84             }
85             });
86             my $self = $xsub->($store, $functype, $wrapper);
87             $self->{store} = $store;
88             $self->{wrapper} = $wrapper;
89             return $self;
90             }
91             else
92             {
93             my ($ptr, $owner) = @_;
94             bless {
95             ptr => $ptr,
96             owner => $owner,
97             }, $class;
98             }
99             });
100              
101              
102             $ffi->attach( call => ['wasm_func_t', 'record(Wasm::Wasmtime::Vec)*', 'record(Wasm::Wasmtime::Vec)*'] => 'wasm_trap_t' => sub {
103             my $xsub = shift;
104             my $self = shift;
105             my @params = $self->type->params;
106             my $args = Wasm::Wasmtime::ValVec->from_perl(\@_, \@params);
107             my $results = $self->result_arity ? Wasm::Wasmtime::ValVec->new($self->result_arity) : undef;
108              
109             my $args_vec = Wasm::Wasmtime::Vec->new(
110             size => scalar @params,
111             data => defined $args ? addressof($args) : undef,
112             );
113              
114             my $results_vec = Wasm::Wasmtime::Vec->new(
115             size => $self->result_arity,
116             data => defined $results ? addressof($results) : undef,
117             );
118              
119             my $trap = $xsub->($self, $args_vec, $results_vec);
120              
121             die $trap if $trap;
122             return unless defined $results;
123             my @results = $results->to_perl;
124             wantarray ? @results : $results[0]; ## no critic (Community::Wantarray)
125             });
126              
127              
128             sub attach
129             {
130 30     30 1 82 my $self = shift;
131 30 100       91 my $package = @_ == 2 ? shift : caller;
132 30         53 my $name = shift;
133 30 100       316 if($package->can($name))
134             {
135 1         163 Carp::carp("attaching ${package}::$name replaces existing subroutine");
136             }
137             Sub::Install::reinstall_sub({
138 32     32   12578 code => sub { $self->call(@_) },
139 30         332 into => $package,
140             as => $name,
141             });
142             }
143              
144              
145             $ffi->attach( type => ['wasm_func_t'] => 'wasm_functype_t' => sub {
146             my($xsub, $self) = @_;
147             my $type = $xsub->($self);
148             $type->{owner} = $self->{owner} || $self;
149             $type;
150             });
151              
152              
153             $ffi->attach( param_arity => ['wasm_func_t'] => 'size_t' => sub {
154             my($xsub, $self) = @_;
155             $xsub->($self);
156             });
157              
158              
159             $ffi->attach( result_arity => ['wasm_func_t'] => 'size_t' => sub {
160             my($xsub, $self) = @_;
161             $xsub->($self);
162             });
163              
164             __PACKAGE__->_cast(0);
165             _generate_destroy();
166              
167             1;
168              
169             __END__