A
Compiler
is used to translate Yoix functions or separate Yoix scripts into bytecode
(actually Java class files is more accurate) that can run on the Java Virtual
Machine.
A function is compiled into bytecode that is associated with the function and
automatically used by the Yoix interpreter whenever it calls that function.
A script is compiled into a special zip archive that usually is saved in a file
that can be executed later by the Yoix interpreter, but only if the command line
that starts the interpreter also includes an option that allows the execution of
zipped archives.
The Yoix interpreter builds and installs a
Compiler
in
VM.compiler
when it starts, so Yoix applications usually do not need to create their own
Compiler.
Yoix programs normally interact with a
Compiler
by reading or writing the following fields:
| addtags |
An
int
that controls whether source file and line number information is included
in code the compiler generates.
A value of
0
(the default) means it will be omitted,
while a non-zero value means source and line number information will be included.
| | alive |
An
int
that is
1
when the compiler is using a separate thread to compile functions that were queued using
compileFunctionLater
and
0
when that thread is not running.
Storing
0
in
alive
kills the thread that is being used to compile queued functions and removes all functions
from the queue.
| | compileFunction(Function func, ...) |
A
Builtin
that compiles one or more functions and returns an
int
that is the number of those functions that were successfully compiled.
Trying to compile a function that is already compiled is harmless,
but will be counted as a successful compilation in the return value.
| | compileFunctionLater(Function func, ...) |
A
Builtin
that queues one or more functions for compilation in a separate thread and returns an
Array
that is a snapshot of the queue.
| | compileScript(String path [, String dest] [, int savesource]) |
A
Builtin
that compiles the Yoix script referenced by
path
and if the compilation is successful it returns a zip archive, as a
String,
that can be written to a file where it can be executed later by the Yoix interpreter,
and if the compilation fails it returns
NULL.
If the optional
dest
argument is supplied then
compileScript
will also try to write the zip archive to that file.
If the optional
savesource
argument is non-zero the script source will also be saved in the zip archive.
Zip archives created by
compileScript
will be rejected by the interpreter if bit 1 in
VM.zipped
is not set, which currently is the default setting.
VM.zipped
is read-only and it can only be changed using the
-z
option, so right now you have to add
-z2
(or
-z3)
to the command line that you use to start the interpreter whenever there's a
compiled script that you want to execute.
As usual the
-?
and
--info
options will give you more information about the command line options that the
interpreter supports.
| | debug |
An
int
that is a collection of flags that can be used to debug the compiler.
Setting bit
0
dumps the generated assembly language, setting bit
1
dumps the Java class file created from that assembly language, and setting bit
2
requests a detailed dump whenever there is a compiler or assembler error.
| | localcopymodel |
An
int
that should be
0
or
1
(the default)
and is used to control how the compiler handles the local variables that it
encounters when it compiles a function or script.
The code generated by the compiler creates the same block data structures
that the interpreter uses, so the compiler always has somewhere it can store
local variables and when
localcopymodel
is
0
the block data structures are the only place they are stored.
Setting
localcopymodel
to
1
means local Yoix
int
and
double
variables will also be represented by primitive int and double variables in the assembly
language that the compiler generates when it is asked to compile a function or script.
Two places to store variables means the compiler has to recognize when the copies need
to be synced and generate code that handles the update.
The overhead rarely exceeds then benefit the compiler gets by being able to manipulate
int and double variables directly using JVM instructions, which run significantly faster
than they would otherwise.
Even though some of them may be implemented, assigning undocumented values to
localcopymodel
should be avoided.
| | priority |
An
int
that is the priority of the thread used to compile the functions queued by
compileFunctionLater.
| | timestamp |
A read-only
String
that is the date associated with this
version
of the compiler.
| | version |
A read-only
String
that is the version assigned to this compiler.
|
Performance improvements from compilation range from nothing
(e.g., in a function that calls Yoix builtins to do most of the work)
to the ridiculous (e.g., 1000 times faster for a function with a loop
that does nothing but increment a counter), with an improvement somewhere
between 10% and 30% as fairly typical.
Measuring the changes can be tricky because compiled functions (or scripts)
are Java classes that have to be loaded and verified by the Java Virtual Machine
before they can start running, so the first execution of a compiled Yoix function
usually takes the most time.
The JVM can also step in at any time and decide to translate the bytecode the
Yoix compiler generated into native machine code and after it does you may
notice another speed improvement.
Right now selective compilation of functions using
compileFunction
or
compileFunctionLater
is probably the best way to use the compiler.
Heavily used functions that don't make excessive use of builtins, particularly
ones that manipulate local
int
and
double
variables, may be good candidates for compilation.
A mechanism that tells the interpreter to automatically compile heavily used
functions probably is something that will be added in a future release.
| |
| Example: |
The first program,
import yoix.*.*;
Sum(int left, int right) = left + right;
VM.compiler.debug = 1;
VM.compiler.compileFunction(Sum);
printf("Sum(7, -3) = %d\n", Sum(7, -3));
prints
Sum(7, -3) = 4
on standard output and since we set the compiler's debug flag to
1
the assembly language generated by the compiler, which looks something like
public class att.research.yoix.$_CompiledClass1 {
extern int att.research.yoix.YoixObject.getInt(int)
extern static att.research.yoix.YoixObject
att.research.yoix.YoixObject.newInt(int)
public static att.research.yoix.YoixObject compiledMethod(
att.research.yoix.YoixObject args,
att.research.yoix.YoixStack stack,
att.research.yoix.SimpleNode[] nodes,
att.research.yoix.YoixObject[] objects
) {
int $N1
push args
push 2
invoke att.research.yoix.YoixObject.getInt(int)
store $N1
int $N2
push args
push 1
invoke att.research.yoix.YoixObject.getInt(int)
store $N2
push $N1
push $N2
add
invoke att.research.yoix.YoixObject.newInt(int)
return
}
}
prints on standard error.
If we put the script
import yoix.*.*;
printf("hello, world\n");
if a file, say
/tmp/script.yx,
then
VM.compiler.compileScript("/tmp/script.yx", "/tmp/compiled.yx");
will compile
/tmp/script.yx
and store the result, which is a special zip archive, in
/tmp/compiled.yx.
Remember, when you want the interpreter to execute
/tmp/compiled.yx
you will need to use the
-z2
or
-z3
command line options, otherwise you will get an
invalidscript
error.
| | |
| See Also: |
|
|