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   1859 use strict;
  278         530  
  278         8094  
3 278     278   1353 use warnings;
  278         544  
  278         7231  
4 278     278   1508 use Carp 'confess';
  278         606  
  278         18002  
5              
6 278     278   121781 use SPVM::BlessedObject;
  278         762  
  278         8351  
7 278     278   122676 use SPVM::BlessedObject::Array;
  278         808  
  278         9025  
8 278     278   124406 use SPVM::BlessedObject::Class;
  278         752  
  278         7986  
9 278     278   125102 use SPVM::BlessedObject::String;
  278         838  
  278         6643  
10              
11 278     278   1742 use SPVM ();
  278         613  
  278         4660  
12 278     278   120856 use SPVM::Builder;
  278         1280  
  278         10775  
13 278     278   2230 use SPVM::ExchangeAPI;
  278         596  
  278         395594  
14              
15             my $API;
16              
17             END {
18 278 100   278   70479780 if ($API) {
19             # Remove circular reference
20 262         1549 my $env = delete $API->{env};
21 262         1051 my $stack = delete $API->{stack};
22            
23 262         5300 $env->destroy_class_vars($stack);
24             }
25             }
26              
27             sub api {
28 13342 100   13342 0 31538 unless ($API) {
29 8         556 &init_api();
30             }
31 13342         44615 return $API;
32             }
33              
34             sub build_module {
35 377     377 0 1107 my ($basic_type_name, $file, $line) = @_;
36            
37 377         1245 &init_api();
38            
39             # Add module informations
40 377         1159 my $build_success;
41 377 50       1756 if (defined $basic_type_name) {
42            
43 377         2063 my $env = $API->env;
44            
45 377         2899 my $compiler = $env->runtime->get_compiler;
46            
47 377         4792 my $start_runtime = $compiler->get_runtime;
48 377         3296 my $start_basic_types_length = $start_runtime->get_basic_types_length;
49            
50 377         3612 $compiler->set_start_file($file);
51 377         3433 $compiler->set_start_line($line);
52 377         2643 my $success = $compiler->compile($basic_type_name);
53 377 50       2902 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         4571 my $runtime = $compiler->get_runtime;
63            
64 377         2633 my $basic_types_length = $runtime->get_basic_types_length;
65            
66 377         2817 for (my $basic_type_id = $start_basic_types_length; $basic_type_id < $basic_types_length; $basic_type_id++) {
67 5954         35404 my $basic_type = $runtime->get_basic_type_by_id($basic_type_id);
68 5954         28519 &load_dynamic_lib($runtime, $basic_type->get_name->to_string);
69             }
70            
71 377         3676 &bind_to_perl($basic_type_name);
72            
73 377         3042 my $stack = $API->stack;
74            
75 377         4273 $env->call_init_methods($stack);
76             }
77             }
78              
79             sub init_api {
80 385 100   385 0 1816 unless ($API) {
81 262         1127 my $build_dir = SPVM::Builder::Util::get_normalized_env('SPVM_BUILD_DIR');
82 262         1170 my $builder = SPVM::Builder->new(build_dir => $build_dir);
83            
84 262         1032 my $builder_compiler = SPVM::Builder::Compiler->new(
85             include_dirs => $builder->include_dirs
86             );
87            
88 262         976 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         644 for my $native_compiler_basic_type_name (@native_compiler_basic_type_names) {
98 1572         6317 $builder_compiler->compile_with_exit($native_compiler_basic_type_name, __FILE__, __LINE__);
99 1572         6413 my $builder_runtime = $builder_compiler->get_runtime;
100            
101             # Load dinamic libnaray - native only
102             {
103 1572         2996 my $basic_type_name = $native_compiler_basic_type_name;
  1572         3272  
104 1572         2504 my $category = 'native';
105 1572         16454 my $method_names = $builder_runtime->get_method_names($basic_type_name, $category);
106            
107 1572 50       5788 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         7289 my $class_file = $builder_runtime->get_class_file($basic_type_name);
111 1572         6249 my $dynamic_lib_file = SPVM::Builder::Util::get_dynamic_lib_file_dist($class_file, $category);
112            
113 1572 50       45548 if (-f $dynamic_lib_file) {
114 1572         7849 my $method_addresses = SPVM::Builder::Util::get_method_addresses($dynamic_lib_file, $basic_type_name, $method_names, $category);
115            
116 1572         13782 for my $method_name (sort keys %$method_addresses) {
117 16506         22315 my $cfunc_address = $method_addresses->{$method_name};
118 16506         51004 $builder_runtime->set_native_method_address($basic_type_name, $method_name, $cfunc_address);
119             }
120             }
121             }
122             }
123             }
124            
125 262         6351 my $builder_env = SPVM::Builder::Env->new($builder_compiler);
126            
127 262         8937 my $builder_stack = $builder_env->new_stack;
128            
129 262         3297 my $builder_api = SPVM::ExchangeAPI->new(env => $builder_env, stack => $builder_stack);
130            
131 262         1947 my $compiler = $builder_api->class("Native::Compiler")->new;
132 262         1580 for my $include_dir (@{$builder->include_dirs}) {
  262         2024  
133 2883         15101 $compiler->add_include_dir($include_dir);
134             }
135 262         3191 $compiler->compile(undef);
136            
137 262         2569 my $env = $builder_api->class("Native::Env")->new($compiler);
138            
139 262         4172 my $stack = $env->new_stack;
140            
141 262         1814 $API = SPVM::ExchangeAPI->new(env => $env, stack => $stack);
142            
143 262         3002 $env->set_command_info_program_name($stack, $0);
144            
145 262         3561 $env->set_command_info_argv($stack, \@ARGV);
146 262         2071 my $base_time = $^T + 0; # For Perl 5.8.9
147 262         2933 $env->set_command_info_base_time($stack, $base_time);
148             }
149             }
150              
151             sub load_dynamic_lib {
152 5954     5954 0 13611 my ($runtime, $basic_type_name) = @_;
153            
154 5954         26808 my $basic_type = $runtime->get_basic_type_by_name($basic_type_name);
155            
156 5954         28117 my $spvm_class_dir = $basic_type->get_class_dir;
157 5954         27174 my $spvm_class_rel_file = $basic_type->get_class_rel_file;
158            
159 5954         14542 for my $category ('precompile', 'native') {
160            
161 11908         32753 my $get_method_names_options = $runtime->__api->new_options({
162             $category => $runtime->__api->class('Int')->new(1)
163             });
164            
165 11908         62203 my $category_method_names;
166            
167 11908 100       35733 if ($category eq 'native') {
    50          
168 5954         36529 $category_method_names = $basic_type->_get_native_method_names;
169             }
170             elsif ($category eq 'precompile') {
171 5954         33241 $category_method_names = $basic_type->_get_precompile_method_names;
172             }
173            
174 11908 100       54915 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       13250 if ($spvm_class_dir) {
179            
180 1587         5037 my $class_file = "$spvm_class_dir/$spvm_class_rel_file";
181 1587         8729 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       48503 unless (-f $dynamic_lib_file) {
185 329         3733 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         3642 my $precompile_source = $runtime->build_precompile_module_source($basic_type)->to_string;
192            
193 329         8306 my $build_dir = SPVM::Builder::Util::get_normalized_env('SPVM_BUILD_DIR');
194 329         5006 my $builder = SPVM::Builder->new(build_dir => $build_dir);
195 329         3721 $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       45751 if (-f $dynamic_lib_file) {
207 1587         14259 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         23841 for my $method_name (sort keys %$method_addresses) {
215 21482         116732 my $method = $basic_type->get_method_by_name($method_name);
216            
217 21482         40688 my $cfunc_address = $method_addresses->{$method_name};
218 21482 100       55040 if ($category eq 'native') {
    50          
219 8648         20862 $method->set_native_address(
220             $runtime->__api->new_address_object($cfunc_address)
221             );
222             }
223             elsif ($category eq 'precompile') {
224 12834         32069 $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 2320 my ($basic_type_name) = @_;
238            
239 377         3380 my $env = $API->env;
240            
241 377         3416 my $compiler = $env->runtime->get_compiler;
242            
243 377         4941 my $runtime = $compiler->get_runtime;
244            
245 377         3386 my $basic_type = $runtime->get_basic_type_by_name($basic_type_name);
246            
247 377         2299 my $perl_basic_type_name_base = "SPVM::";
248 377         2113 my $perl_basic_type_name = "$perl_basic_type_name_base$basic_type_name";
249            
250 377 100       2746 unless ($BIND_TO_PERL_BASIC_TYPE_NAME_H->{$perl_basic_type_name}) {
251            
252 375         4957 my $parent_basic_type = $basic_type->get_parent;
253            
254             # The inheritance
255 375         1931 my @isa;
256 375 50       2381 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         1946 push @isa, 'SPVM::BlessedObject::Class';
261 375         2652 my $isa = "our \@ISA = (" . join(',', map { "'$_'" } @isa) . ");";
  375         4242  
262            
263 375         2307 my $code = "package $perl_basic_type_name; $isa";
264 375         75614 eval $code;
265            
266 375 50       4312 if (my $error = $@) {
267 0         0 confess $error;
268             }
269            
270 375         5592 my $methods_length = $basic_type->get_methods_length;
271 375         3510 for (my $method_index = 0; $method_index < $methods_length; $method_index++) {
272 6993         40372 my $method = $basic_type->get_method_by_index($method_index);
273            
274 6993         31636 my $method_name = $method->get_name->to_string;
275            
276             # Destrutor is skip
277 6993 100       51561 if ($method_name eq 'DESTROY') {
    50          
278 2         21 next;
279             }
280             # Anon method is skip
281             elsif (length $method_name == 0) {
282 0         0 next;
283             }
284            
285 6991         17893 my $perl_method_abs_name = "${perl_basic_type_name}::$method_name";
286 6991         34979 my $is_class_method = $method->is_class_method;
287            
288 6991 100       20936 if ($is_class_method) {
289             # Define Perl method
290 278     278   2889 no strict 'refs';
  278         684  
  278         57090  
291            
292             # Suppress refer to objects
293 6097         13606 my $basic_type_name_string = "$basic_type_name";
294 6097         10967 my $method_name_string = "$method_name";
295            
296 6097         93973 *{"$perl_method_abs_name"} = sub {
297 12364     12364   2500160 my $perl_basic_type_name = shift;
298            
299 12364         17939 my $return_value;
300            
301 12364         17657 eval { $return_value = SPVM::api()->call_method($basic_type_name_string, $method_name_string, @_) };
  12364         29421  
302 12364         42657 my $error = $@;
303 12364 100       23944 if ($error) {
304 150         16814 confess $error;
305             }
306 12214         52218 $return_value;
307 6097         37638 };
308             }
309             }
310            
311 375         5224 $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