File Coverage

blib/lib/SPVM/Global.pm
Criterion Covered Total %
statement 162 171 94.7
branch 33 44 75.0
condition n/a
subroutine 18 18 100.0
pod 0 5 0.0
total 213 238 89.5


line stmt bran cond sub pod time code
1             package SPVM::Global;
2 278     278   1843 use strict;
  278         502  
  278         7965  
3 278     278   1372 use warnings;
  278         552  
  278         7090  
4 278     278   1508 use Carp 'confess';
  278         602  
  278         16776  
5              
6 278     278   118858 use SPVM::BlessedObject;
  278         745  
  278         8350  
7 278     278   120405 use SPVM::BlessedObject::Array;
  278         800  
  278         10336  
8 278     278   121838 use SPVM::BlessedObject::Class;
  278         806  
  278         7977  
9 278     278   121441 use SPVM::BlessedObject::String;
  278         765  
  278         6680  
10              
11 278     278   1709 use SPVM ();
  278         552  
  278         4824  
12 278     278   119145 use SPVM::Builder;
  278         1214  
  278         10338  
13 278     278   2239 use SPVM::ExchangeAPI;
  278         556  
  278         392953  
14              
15             my $API;
16              
17             END {
18 278 100   278   68438815 if ($API) {
19             # Remove circular reference
20 262         1495 my $env = delete $API->{env};
21 262         1031 my $stack = delete $API->{stack};
22            
23 262         4967 $env->destroy_class_vars($stack);
24             }
25             }
26              
27             sub api {
28 13342 100   13342 0 32536 unless ($API) {
29 8         530 &init_api();
30             }
31 13342         43171 return $API;
32             }
33              
34             sub build_module {
35 377     377 0 1037 my ($basic_type_name, $file, $line) = @_;
36            
37 377         1185 &init_api();
38            
39             # Add module informations
40 377         1133 my $build_success;
41 377 50       1664 if (defined $basic_type_name) {
42            
43 377         2025 my $env = $API->env;
44            
45 377         2845 my $compiler = $env->runtime->get_compiler;
46            
47 377         4721 my $start_runtime = $compiler->get_runtime;
48 377         3228 my $start_basic_types_length = $start_runtime->get_basic_types_length;
49            
50 377         3385 $compiler->set_start_file($file);
51 377         3354 $compiler->set_start_line($line);
52 377         2585 my $success = $compiler->compile($basic_type_name);
53 377 50       2862 unless ($success) {
54 0         0 my $error_messages = $compiler->get_error_messages;
55 0         0 for my $error_message (@$error_messages) {
56 0         0 printf STDERR "[CompileError]$error_message\n";
57             }
58 0         0 $compiler = undef;
59 0         0 exit(255);
60             }
61            
62 377         4822 my $runtime = $compiler->get_runtime;
63            
64 377         2784 my $basic_types_length = $runtime->get_basic_types_length;
65            
66 377         2706 for (my $basic_type_id = $start_basic_types_length; $basic_type_id < $basic_types_length; $basic_type_id++) {
67 5954         34804 my $basic_type = $runtime->get_basic_type_by_id($basic_type_id);
68 5954         29112 &load_dynamic_lib($runtime, $basic_type->get_name->to_string);
69             }
70            
71 377         3651 &bind_to_perl($basic_type_name);
72            
73 377         2824 my $stack = $API->stack;
74            
75 377         4233 $env->call_init_methods($stack);
76             }
77             }
78              
79             sub init_api {
80 385 100   385 0 1766 unless ($API) {
81 262         1129 my $build_dir = SPVM::Builder::Util::get_normalized_env('SPVM_BUILD_DIR');
82 262         1082 my $builder = SPVM::Builder->new(build_dir => $build_dir);
83            
84 262         1047 my $builder_compiler = SPVM::Builder::Compiler->new(
85             include_dirs => $builder->include_dirs
86             );
87            
88 262         930 my @native_compiler_basic_type_names = qw(
89             Native::Compiler
90             Native::Method
91             Native::Runtime
92             Native::BasicType
93             Native::Stack
94             Native::Env
95             );
96            
97 262         640 for my $native_compiler_basic_type_name (@native_compiler_basic_type_names) {
98 1572         6096 $builder_compiler->compile_with_exit($native_compiler_basic_type_name, __FILE__, __LINE__);
99 1572         6055 my $builder_runtime = $builder_compiler->get_runtime;
100            
101             # Load dinamic libnaray - native only
102             {
103 1572         2931 my $basic_type_name = $native_compiler_basic_type_name;
  1572         3236  
104 1572         2875 my $category = 'native';
105 1572         16072 my $method_names = $builder_runtime->get_method_names($basic_type_name, $category);
106            
107 1572 50       6028 if (@$method_names) {
108             # Build classes - Compile C source codes and link them to SPVM precompile method
109             # Shared library which is already installed in distribution directory
110 1572         7238 my $class_file = $builder_runtime->get_class_file($basic_type_name);
111 1572         6018 my $dynamic_lib_file = SPVM::Builder::Util::get_dynamic_lib_file_dist($class_file, $category);
112            
113 1572 50       46620 if (-f $dynamic_lib_file) {
114 1572         7877 my $method_addresses = SPVM::Builder::Util::get_method_addresses($dynamic_lib_file, $basic_type_name, $method_names, $category);
115            
116 1572         13397 for my $method_name (sort keys %$method_addresses) {
117 16506         21480 my $cfunc_address = $method_addresses->{$method_name};
118 16506         49362 $builder_runtime->set_native_method_address($basic_type_name, $method_name, $cfunc_address);
119             }
120             }
121             }
122             }
123             }
124            
125 262         6429 my $builder_env = SPVM::Builder::Env->new($builder_compiler);
126            
127 262         8628 my $builder_stack = $builder_env->new_stack;
128            
129 262         3181 my $builder_api = SPVM::ExchangeAPI->new(env => $builder_env, stack => $builder_stack);
130            
131 262         1812 my $compiler = $builder_api->class("Native::Compiler")->new;
132 262         1564 for my $include_dir (@{$builder->include_dirs}) {
  262         2006  
133 2883         15783 $compiler->add_include_dir($include_dir);
134             }
135 262         3368 $compiler->compile(undef);
136            
137 262         2306 my $env = $builder_api->class("Native::Env")->new($compiler);
138            
139 262         4012 my $stack = $env->new_stack;
140            
141 262         1781 $API = SPVM::ExchangeAPI->new(env => $env, stack => $stack);
142            
143 262         3004 $env->set_command_info_program_name($stack, $0);
144            
145 262         3430 $env->set_command_info_argv($stack, \@ARGV);
146 262         1933 my $base_time = $^T + 0; # For Perl 5.8.9
147 262         2973 $env->set_command_info_base_time($stack, $base_time);
148             }
149             }
150              
151             sub load_dynamic_lib {
152 5954     5954 0 13010 my ($runtime, $basic_type_name) = @_;
153            
154 5954         27038 my $basic_type = $runtime->get_basic_type_by_name($basic_type_name);
155            
156 5954         28376 my $spvm_class_dir = $basic_type->get_class_dir;
157 5954         28370 my $spvm_class_rel_file = $basic_type->get_class_rel_file;
158            
159 5954         14329 for my $category ('precompile', 'native') {
160            
161 11908         31396 my $get_method_names_options = $runtime->__api->new_options({
162             $category => $runtime->__api->class('Int')->new(1)
163             });
164            
165 11908         60752 my $category_method_names;
166            
167 11908 100       35024 if ($category eq 'native') {
    50          
168 5954         34916 $category_method_names = $basic_type->_get_native_method_names;
169             }
170             elsif ($category eq 'precompile') {
171 5954         32657 $category_method_names = $basic_type->_get_precompile_method_names;
172             }
173            
174 11908 100       53269 if (@$category_method_names) {
175             # Build modules - Compile C source codes and link them to SPVM precompile method
176             # Shared library which is already installed in distribution directory
177            
178 1587 50       12255 if ($spvm_class_dir) {
179            
180 1587         4754 my $class_file = "$spvm_class_dir/$spvm_class_rel_file";
181 1587         8573 my $dynamic_lib_file = SPVM::Builder::Util::get_dynamic_lib_file_dist($class_file, $category);
182            
183             # Try to build the shared library at runtime if shared library is not found
184 1587 100       48109 unless (-f $dynamic_lib_file) {
185 329         3643 my $dl_func_list = SPVM::Builder::Util::create_dl_func_list(
186             $basic_type_name,
187             $category_method_names,
188             {category => $category}
189             );
190            
191 329         3444 my $precompile_source = $runtime->build_precompile_module_source($basic_type)->to_string;
192            
193 329         7650 my $build_dir = SPVM::Builder::Util::get_normalized_env('SPVM_BUILD_DIR');
194 329         4920 my $builder = SPVM::Builder->new(build_dir => $build_dir);
195 329         3432 $dynamic_lib_file = $builder->build_at_runtime(
196             $basic_type_name,
197             {
198             class_file => $class_file,
199             category => $category,
200             dl_func_list => $dl_func_list,
201             precompile_source => $precompile_source
202             }
203             );
204             }
205            
206 1587 50       43357 if (-f $dynamic_lib_file) {
207 1587         13243 my $method_addresses = SPVM::Builder::Util::get_method_addresses(
208             $dynamic_lib_file,
209             $basic_type_name,
210             $category_method_names,
211             $category
212             );
213            
214 1587         22638 for my $method_name (sort keys %$method_addresses) {
215 21482         117907 my $method = $basic_type->get_method_by_name($method_name);
216            
217 21482         40957 my $cfunc_address = $method_addresses->{$method_name};
218 21482 100       52806 if ($category eq 'native') {
    50          
219 8648         20433 $method->set_native_address(
220             $runtime->__api->new_address_object($cfunc_address)
221             );
222             }
223             elsif ($category eq 'precompile') {
224 12834         31484 $method->set_precompile_address(
225             $runtime->__api->new_address_object($cfunc_address)
226             );
227             }
228             }
229             }
230             }
231             }
232             }
233             }
234              
235             my $BIND_TO_PERL_BASIC_TYPE_NAME_H = {};
236             sub bind_to_perl {
237 377     377 0 2199 my ($basic_type_name) = @_;
238            
239 377         3041 my $env = $API->env;
240            
241 377         3285 my $compiler = $env->runtime->get_compiler;
242            
243 377         4875 my $runtime = $compiler->get_runtime;
244            
245 377         3453 my $basic_type = $runtime->get_basic_type_by_name($basic_type_name);
246            
247 377         2268 my $perl_basic_type_name_base = "SPVM::";
248 377         2107 my $perl_basic_type_name = "$perl_basic_type_name_base$basic_type_name";
249            
250 377 100       2802 unless ($BIND_TO_PERL_BASIC_TYPE_NAME_H->{$perl_basic_type_name}) {
251            
252 375         4921 my $parent_basic_type = $basic_type->get_parent;
253            
254             # The inheritance
255 375         1790 my @isa;
256 375 50       2380 if (defined $parent_basic_type) {
257 0         0 my $parent_basic_type_name = $parent_basic_type->get_name->to_string;
258 0         0 push @isa, "$perl_basic_type_name_base$parent_basic_type_name";
259             }
260 375         1815 push @isa, 'SPVM::BlessedObject::Class';
261 375         2434 my $isa = "our \@ISA = (" . join(',', map { "'$_'" } @isa) . ");";
  375         4077  
262            
263 375         2225 my $code = "package $perl_basic_type_name; $isa";
264 375         73054 eval $code;
265            
266 375 50       4408 if (my $error = $@) {
267 0         0 confess $error;
268             }
269            
270 375         5418 my $methods_length = $basic_type->get_methods_length;
271 375         3388 for (my $method_index = 0; $method_index < $methods_length; $method_index++) {
272 6993         39292 my $method = $basic_type->get_method_by_index($method_index);
273            
274 6993         31880 my $method_name = $method->get_name->to_string;
275            
276             # Destrutor is skip
277 6993 100       50180 if ($method_name eq 'DESTROY') {
    50          
278 2         42 next;
279             }
280             # Anon method is skip
281             elsif (length $method_name == 0) {
282 0         0 next;
283             }
284            
285 6991         17512 my $perl_method_abs_name = "${perl_basic_type_name}::$method_name";
286 6991         33270 my $is_class_method = $method->is_class_method;
287            
288 6991 100       19786 if ($is_class_method) {
289             # Define Perl method
290 278     278   2845 no strict 'refs';
  278         641  
  278         55725  
291            
292             # Suppress refer to objects
293 6097         13545 my $basic_type_name_string = "$basic_type_name";
294 6097         10996 my $method_name_string = "$method_name";
295            
296 6097         90462 *{"$perl_method_abs_name"} = sub {
297 12364     12364   2466468 my $perl_basic_type_name = shift;
298            
299 12364         17198 my $return_value;
300            
301 12364         17720 eval { $return_value = SPVM::api()->call_method($basic_type_name_string, $method_name_string, @_) };
  12364         28061  
302 12364         42371 my $error = $@;
303 12364 100       23951 if ($error) {
304 150         15670 confess $error;
305             }
306 12214         53293 $return_value;
307 6097         35830 };
308             }
309             }
310            
311 375         5060 $BIND_TO_PERL_BASIC_TYPE_NAME_H->{$perl_basic_type_name} = 1;
312             }
313             }
314              
315             =head1 Name
316              
317             SPVM::Global - SPVM Global Instance for Perl Interpreter
318              
319             =head1 Copyright & License
320              
321             Copyright (c) 2023 Yuki Kimoto
322              
323             MIT License