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   1820 use strict;
  278         518  
  278         7789  
3 278     278   1310 use warnings;
  278         509  
  278         6698  
4 278     278   1378 use Carp 'confess';
  278         551  
  278         16321  
5              
6 278     278   113157 use SPVM::BlessedObject;
  278         733  
  278         8013  
7 278     278   116160 use SPVM::BlessedObject::Array;
  278         749  
  278         8741  
8 278     278   118040 use SPVM::BlessedObject::Class;
  278         749  
  278         8014  
9 278     278   117935 use SPVM::BlessedObject::String;
  278         751  
  278         6474  
10              
11 278     278   1602 use SPVM ();
  278         555  
  278         4419  
12 278     278   113451 use SPVM::Builder;
  278         1066  
  278         9639  
13 278     278   2004 use SPVM::ExchangeAPI;
  278         539  
  278         373455  
14              
15             my $API;
16              
17             END {
18 278 100   278   70129756 if ($API) {
19             # Remove circular reference
20 262         1345 my $env = delete $API->{env};
21 262         955 my $stack = delete $API->{stack};
22            
23 262         4806 $env->destroy_class_vars($stack);
24             }
25             }
26              
27             sub api {
28 13374 100   13374 0 31434 unless ($API) {
29 8         546 &init_api();
30             }
31 13374         42609 return $API;
32             }
33              
34             sub build_module {
35 379     379 0 1005 my ($basic_type_name, $file, $line) = @_;
36            
37 379         1182 &init_api();
38            
39             # Add module informations
40 379         1042 my $build_success;
41 379 50       1582 if (defined $basic_type_name) {
42            
43 379         1776 my $env = $API->env;
44            
45 379         2868 my $compiler = $env->runtime->get_compiler;
46            
47 379         4434 my $start_runtime = $compiler->get_runtime;
48 379         2699 my $start_basic_types_length = $start_runtime->get_basic_types_length;
49            
50 379         2877 $compiler->set_start_file($file);
51 379         2976 $compiler->set_start_line($line);
52 379         2167 my $success = $compiler->compile($basic_type_name);
53 379 50       2443 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 379         3850 my $runtime = $compiler->get_runtime;
63            
64 379         2464 my $basic_types_length = $runtime->get_basic_types_length;
65            
66 379         2165 for (my $basic_type_id = $start_basic_types_length; $basic_type_id < $basic_types_length; $basic_type_id++) {
67 6054         34960 my $basic_type = $runtime->get_basic_type_by_id($basic_type_id);
68 6054         28148 &load_dynamic_lib($runtime, $basic_type->get_name->to_string);
69             }
70            
71 379         3147 &bind_to_perl($basic_type_name);
72            
73 379         2522 my $stack = $API->stack;
74            
75 379         4207 $env->call_init_methods($stack);
76             }
77             }
78              
79             sub init_api {
80 387 100   387 0 1622 unless ($API) {
81 262         1096 my $build_dir = SPVM::Builder::Util::get_normalized_env('SPVM_BUILD_DIR');
82 262         1091 my $builder = SPVM::Builder->new(build_dir => $build_dir);
83            
84 262         1040 my $builder_compiler = SPVM::Builder::Compiler->new(
85             include_dirs => $builder->include_dirs
86             );
87            
88 262         915 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         609 for my $native_compiler_basic_type_name (@native_compiler_basic_type_names) {
98 1572         5987 $builder_compiler->compile_with_exit($native_compiler_basic_type_name, __FILE__, __LINE__);
99 1572         5597 my $builder_runtime = $builder_compiler->get_runtime;
100            
101             # Load dinamic libnaray - native only
102             {
103 1572         2803 my $basic_type_name = $native_compiler_basic_type_name;
  1572         2911  
104 1572         2400 my $category = 'native';
105 1572         15398 my $method_names = $builder_runtime->get_method_names($basic_type_name, $category);
106            
107 1572 50       5337 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         7124 my $class_file = $builder_runtime->get_class_file($basic_type_name);
111 1572         5792 my $dynamic_lib_file = SPVM::Builder::Util::get_dynamic_lib_file_dist($class_file, $category);
112            
113 1572 50       39001 if (-f $dynamic_lib_file) {
114 1572         7469 my $method_addresses = SPVM::Builder::Util::get_method_addresses($dynamic_lib_file, $basic_type_name, $method_names, $category);
115            
116 1572         12299 for my $method_name (sort keys %$method_addresses) {
117 16506         21202 my $cfunc_address = $method_addresses->{$method_name};
118 16506         47965 $builder_runtime->set_native_method_address($basic_type_name, $method_name, $cfunc_address);
119             }
120             }
121             }
122             }
123             }
124            
125 262         5724 my $builder_env = SPVM::Builder::Env->new($builder_compiler);
126            
127 262         8234 my $builder_stack = $builder_env->new_stack;
128            
129 262         2834 my $builder_api = SPVM::ExchangeAPI->new(env => $builder_env, stack => $builder_stack);
130            
131 262         1670 my $compiler = $builder_api->class("Native::Compiler")->new;
132 262         1355 for my $include_dir (@{$builder->include_dirs}) {
  262         1829  
133 2883         14768 $compiler->add_include_dir($include_dir);
134             }
135 262         2685 $compiler->compile(undef);
136            
137 262         2091 my $env = $builder_api->class("Native::Env")->new($compiler);
138            
139 262         3677 my $stack = $env->new_stack;
140            
141 262         1494 $API = SPVM::ExchangeAPI->new(env => $env, stack => $stack);
142            
143 262         2746 $env->set_command_info_program_name($stack, $0);
144            
145 262         2720 $env->set_command_info_argv($stack, \@ARGV);
146 262         1271 my $base_time = $^T + 0; # For Perl 5.8.9
147 262         2914 $env->set_command_info_base_time($stack, $base_time);
148             }
149             }
150              
151             sub load_dynamic_lib {
152 6054     6054 0 13207 my ($runtime, $basic_type_name) = @_;
153            
154 6054         26466 my $basic_type = $runtime->get_basic_type_by_name($basic_type_name);
155            
156 6054         27685 my $spvm_class_dir = $basic_type->get_class_dir;
157 6054         26992 my $spvm_class_rel_file = $basic_type->get_class_rel_file;
158            
159 6054         13752 for my $category ('precompile', 'native') {
160            
161 12108         31863 my $get_method_names_options = $runtime->__api->new_options({
162             $category => $runtime->__api->class('Int')->new(1)
163             });
164            
165 12108         61135 my $category_method_names;
166            
167 12108 100       34918 if ($category eq 'native') {
    50          
168 6054         35551 $category_method_names = $basic_type->_get_native_method_names;
169             }
170             elsif ($category eq 'precompile') {
171 6054         33018 $category_method_names = $basic_type->_get_precompile_method_names;
172             }
173            
174 12108 100       54078 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 1617 50       11848 if ($spvm_class_dir) {
179            
180 1617         4581 my $class_file = "$spvm_class_dir/$spvm_class_rel_file";
181 1617         8103 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 1617 100       44112 unless (-f $dynamic_lib_file) {
185 341         3268 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 341         3517 my $precompile_source = $runtime->build_precompile_module_source($basic_type)->to_string;
192            
193 341         8178 my $build_dir = SPVM::Builder::Util::get_normalized_env('SPVM_BUILD_DIR');
194 341         4801 my $builder = SPVM::Builder->new(build_dir => $build_dir);
195 341         3373 $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 1617 50       39831 if (-f $dynamic_lib_file) {
207 1617         12006 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 1617         21715 for my $method_name (sort keys %$method_addresses) {
215 22198         115580 my $method = $basic_type->get_method_by_name($method_name);
216            
217 22198         42047 my $cfunc_address = $method_addresses->{$method_name};
218 22198 100       56963 if ($category eq 'native') {
    50          
219 9048         21090 $method->set_native_address(
220             $runtime->__api->new_address_object($cfunc_address)
221             );
222             }
223             elsif ($category eq 'precompile') {
224 13150         31018 $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 379     379 0 2033 my ($basic_type_name) = @_;
238            
239 379         2908 my $env = $API->env;
240            
241 379         3141 my $compiler = $env->runtime->get_compiler;
242            
243 379         4419 my $runtime = $compiler->get_runtime;
244            
245 379         3047 my $basic_type = $runtime->get_basic_type_by_name($basic_type_name);
246            
247 379         1946 my $perl_basic_type_name_base = "SPVM::";
248 379         1809 my $perl_basic_type_name = "$perl_basic_type_name_base$basic_type_name";
249            
250 379 100       2479 unless ($BIND_TO_PERL_BASIC_TYPE_NAME_H->{$perl_basic_type_name}) {
251            
252 377         4567 my $parent_basic_type = $basic_type->get_parent;
253            
254             # The inheritance
255 377         1416 my @isa;
256 377 50       2245 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 377         1715 push @isa, 'SPVM::BlessedObject::Class';
261 377         2190 my $isa = "our \@ISA = (" . join(',', map { "'$_'" } @isa) . ");";
  377         3738  
262            
263 377         2150 my $code = "package $perl_basic_type_name; $isa";
264 377         62010 eval $code;
265            
266 377 50       3838 if (my $error = $@) {
267 0         0 confess $error;
268             }
269            
270 377         5170 my $methods_length = $basic_type->get_methods_length;
271 377         3278 for (my $method_index = 0; $method_index < $methods_length; $method_index++) {
272 7489         41386 my $method = $basic_type->get_method_by_index($method_index);
273            
274 7489         33141 my $method_name = $method->get_name->to_string;
275            
276             # Destrutor is skip
277 7489 100       52943 if ($method_name eq 'DESTROY') {
    50          
278 2         16 next;
279             }
280             # Anon method is skip
281             elsif (length $method_name == 0) {
282 0         0 next;
283             }
284            
285 7487         18601 my $perl_method_abs_name = "${perl_basic_type_name}::$method_name";
286 7487         34481 my $is_class_method = $method->is_class_method;
287            
288 7487 100       21335 if ($is_class_method) {
289             # Define Perl method
290 278     278   2902 no strict 'refs';
  278         650  
  278         53729  
291            
292             # Suppress refer to objects
293 6567         13690 my $basic_type_name_string = "$basic_type_name";
294 6567         10842 my $method_name_string = "$method_name";
295            
296 6567         93415 *{"$perl_method_abs_name"} = sub {
297 12396     12396   2362670 my $perl_basic_type_name = shift;
298            
299 12396         18015 my $return_value;
300            
301 12396         18210 eval { $return_value = SPVM::api()->call_method($basic_type_name_string, $method_name_string, @_) };
  12396         27868  
302 12396         42522 my $error = $@;
303 12396 100       24533 if ($error) {
304 150         15910 confess $error;
305             }
306 12246         51137 $return_value;
307 6567         36075 };
308             }
309             }
310            
311 377         4805 $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