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   593 use strict;
  16         35  
  16         486  
4 16     16   76 use warnings;
  16         36  
  16         409  
5 16     16   263 use 5.008004;
  16         52  
6 16     16   100 use base qw( Wasm::Wasmtime::Extern );
  16         38  
  16         2163  
7 16     16   169 use Ref::Util qw( is_blessed_ref is_plain_arrayref );
  16         30  
  16         915  
8 16     16   119 use Wasm::Wasmtime::FFI;
  16         35  
  16         1614  
9 16     16   5454 use Wasm::Wasmtime::FuncType;
  16         50  
  16         540  
10 16     16   4775 use Wasm::Wasmtime::Trap;
  16         47  
  16         566  
11 16     16   110 use FFI::C::Util qw( set_array_count );
  16         50  
  16         900  
12 16     16   108 use Sub::Install;
  16         33  
  16         157  
13 16     16   441 use Carp ();
  16         54  
  16         344  
14 16     16   98 use constant is_func => 1;
  16         31  
  16         951  
15 16     16   96 use constant kind => 'func';
  16         37  
  16         1965  
16             use overload
17 1     1   3 '&{}' => sub { my $self = shift; sub { $self->call(@_) } },
  1         5  
  1         7  
18 14     14   1146 bool => sub { 1 },
19 16     16   119 fallback => 1;
  16         31  
  16         185  
20             ;
21              
22             # ABSTRACT: Wasmtime function class
23             our $VERSION = '0.21'; # 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);
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             $ffi->attach( call => ['wasm_func_t', 'wasm_val_vec_t', 'wasm_val_vec_t'] => 'wasm_trap_t' => sub {
104             my $xsub = shift;
105             my $self = shift;
106             my $args = Wasm::Wasmtime::ValVec->from_perl(\@_, [$self->type->params]);
107             my $results = $self->result_arity ? Wasm::Wasmtime::ValVec->new($self->result_arity) : undef;
108              
109             my $trap = $xsub->($self, $args, $results);
110              
111             die $trap if $trap;
112             return unless defined $results;
113             my @results = $results->to_perl;
114             wantarray ? @results : $results[0]; ## no critic (Freenode::Wantarray)
115             });
116              
117              
118             sub attach
119             {
120 30     30 1 1182 my $self = shift;
121 30 100       84 my $package = @_ == 2 ? shift : caller;
122 30         50 my $name = shift;
123 30 100       308 if($package->can($name))
124             {
125 1         174 Carp::carp("attaching ${package}::$name replaces existing subroutine");
126             }
127             Sub::Install::reinstall_sub({
128 32     32   18411 code => sub { $self->call(@_) },
129 30         368 into => $package,
130             as => $name,
131             });
132             }
133              
134              
135             $ffi->attach( type => ['wasm_func_t'] => 'wasm_functype_t' => sub {
136             my($xsub, $self) = @_;
137             my $type = $xsub->($self);
138             $type->{owner} = $self->{owner} || $self;
139             $type;
140             });
141              
142              
143             $ffi->attach( param_arity => ['wasm_func_t'] => 'size_t' => sub {
144             my($xsub, $self) = @_;
145             $xsub->($self);
146             });
147              
148              
149             $ffi->attach( result_arity => ['wasm_func_t'] => 'size_t' => sub {
150             my($xsub, $self) = @_;
151             $xsub->($self);
152             });
153              
154             __PACKAGE__->_cast(0);
155             _generate_destroy();
156              
157             1;
158              
159             __END__