Consider the following two programs:
unit module Comp;
say 'Hello, world!'
and
unit module Comp;
CHECK { if $*DISTRO.is-win { say 'compiling on Windows' }}
say 'Hello, world!'
Naively, I would have expected both programs to compile to exactly the same bytecode: the CHECK
block specifies code to run at the end of compilation; checking a variable and then doing nothing has no effect on the run-time behavior of the program, and thus (I would have thought) shouldn't need to be included in the compiled bytecode.
However, compiling these two programs does not result in the same bytecode. Specifically, compiling the version without the CHECK
block creates 24K of bytecode versus 60K for the version with it. Why is the bytecode different for these two versions? Does this difference in bytecode have (or potentially have) a runtime cost? (It seems like it must, but I want to be sure).
And one more related question: how do DOC CHECK
blocks fit in with the above? My understanding is that even the compiler skips DOC CHECK
blocks when it's not run with the --doc
flag. Consistent with that, the bytecode for a hello-world program does not increase in size when given a DOC CHECK
block like the one above. However, it does increase in size if the block includes a use
statement. From that, I conclude that use
is somehow special-cased and gets executed even in DOC CHECK
blocks. Is that correct? If so, are there other simillarly special-cased forms I should know about?
After the first compilation, the bytecode generated is now run by the Java Virtual Machine and not the processor in consideration. This essentially means that we only need to have basic java installation on any platforms that we want to run our code on.
Compile time vs Runtime Compile-time and Runtime are the two programming terms used in the software development. Compile-time is the time at which the source code is converted into an executable code while the run time is the time at which the executable code is started running. Both the compile-time and runtime refer to different types of error.
Resources required to run the bytecode are made available by theJava Virtual Machine, which calls the processor to allocate the required resources. JVM's are stack-based so they stack implementation to read the codes.
Compile time address binding is done before loading the program into memory. Execution time address binding is done at the time of program execution. Instructions are translated into absolute address.
A CHECK
or BEGIN
block (or other BEGIN
-time constructs) may contain code that escapes. For example:
BEGIN SomeClass.^add_method('foo', anon method foo() { 42 })
Adds a method to a class, which exists beyond the bounds of the BEGIN
block. That method's bytecode is therefore required in the compiled output. Currently, Rakudo conservatively includes the bytecode of everything in a BEGIN
or CHECK
block. It may be possible to avoid that for some simple cases in the future.
So far as the runtime cost goes, the implementation goes to some lengths to minimize the cost of bytecode that is never run (not so much for this case, but because the standard library is huge but many programs use only a fraction of it). For example:
mmap
'd, so some unused parts of it may not actually be paged into memorySo far as use
goes, its action is performed as soon as it is parsed. Being inside a DOC CHECK
block does not suppress that - and in general can not, because the use
might bring in things that need to be known in order to finish parsing the contents of that block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With