Usage:
package require TJC
TJC::package package
TJC::command procname
classname
TJC::compile cmd
TJC is implemented as part of Jacl and includes runtime
support for TJC compiled procedures. The TJC package is loaded into
Jacl via the following Tcl command:
% package require TJC
1.0
The
TJC package defines
the
TJC namespace and
adds three Tcl commands to the
TJC
namespace. The
TJC::package
command is used to load a TJC compiled package into the Jacl
interpreter. Loading a TJC compiled package will source each of the Tcl
scripts included in the package and define each of the compiled Tcl
commands included in the package. In the following example, a TJC
compiled package named
foo.bar.baz
is loaded.
% TJC::package foo.bar.baz
A TJC package is initialized by loading a class named
TJCExtension from the named
package. This class implements the standard Extension API for Jacl
extensions, so one could also load a TJC package via the
java::load command as follows:
% java::load
foo.bar.baz.TJCExtension
The benefit of the
TJC::package
command is that it is simpler and it can be used even when the
java package has not been
loaded into Jacl.
The
TJC::command Tcl
command is normally used only by the internal implementation of TJC.
End users will not need to invoke the this command. The command is used
to associate a Tcl command name with a compiled Java class file. When a
Tcl script is parsed, it is scanned for proc declaration that can be
compiled. The code for compiled proc declarations is then replaced with
a call to
TJC::command.
Original Tcl Script:
set i 0
proc hello {}
{ return "Hello World" }
Modified Tcl Script:
set i 0
TJC::command
hello foo.bar.baz.HelloCmd
At runtime, a
[TJC::package
foo.bar.baz] command would cause the modified Tcl script to be
evaluated. The modified Tcl script would define the
hello command using the
compiled implementation in the Java class named
HelloCmd.
Compiling Tcl procs at runtime
Support for compiling Tcl procedures at runtime is included as part of
the TJC package. Using
TJC::compile,
one can compile a Tcl proc into Java source code and then into Java
byte code. The Java byte code implementation of the command will then
be loaded into the interpreter. Note that this runtime compilation is
not started by default and there is no means to automatically compile
all Tcl procs that are defined in the interpreter. The user needs to
explicitly indicate which procs should be compiled after the procs have
been defined. The most simple usage is the following.
package require TJC
proc hello {} {
return "Hello
World"
}
TJC::compile hello
The above invocation will start a second thread to do the compilation.
When the command has been compiled, the Tcl proc hello will be replaced
with a compiled version that performs the same operations as the Tcl
proc. Most users will only ever need to use the
TJC::compile command as shown
above.
In the example above, the user has no way of knowing when the compile
job is finished. If the user needs to be informed when the compile job
is done, the
TJC::compile
command supports notification via a callback or via a variable. The
following shows how a callback can be invoked when a compile job is
done.
package require TJC
proc hello {} {
return "Hello
World"
}
proc my_hello_ready { status cmd
msg } {
if {$status ==
"OK"} {
puts "command \"$cmd\" was compiled"
} else {
puts "command \"$cmd\" could not be compiled: $msg"
}
}
TJC::compile hello -readycmd
my_hello_ready
(after waiting a moment, the
following should be printed)
command "::hello" was compiled
In the example above, the callback is invoked with a status string that
can be "OK" or "ERROR". The cmd argument is the fully qualified name of
the compiled command. The msg argument is a string indicating a
compiler error if status is not "OK".
In following example, notification is implemented with a variable. The
example sets a variable when the command has been compiled and
installed. The value that the ready variable is set to is the same as
the arguments to the
-readycmd
command.
package require TJC
proc hello {} {
return "Hello
World"
}
TJC::compile hello -readyvar
my_hello_ready
vwait my_hello_ready
puts $my_hello_ready
(after a moment, the following
should be printed)
OK ::hello {}
Compiling Java classes at runtime
TJC::command can also be
used to compile source code for a Java class into byte code at runtime.
This functionality makes it easy to add dynamic generation of Java code
to an application. It can be extremely powerfull when used with the
java package. The following example shows how a static Java method can
be compiled and invoked.
package require TJC
package require java
set jclass mytest.dynamic.Test1
set jsrc {
package mytest.dynamic;
public class Test1 {
public static
String call() {
return "CALLED";
}
}
}
set jinfo [list $jclass $jsrc]
TJC::compile -java $jinfo
-readyvar my_class_ready
vwait my_class_ready
puts $my_class_ready
(after a moment, the following should be printed)
OK mytest.dynamic.Test1 {}
(since the class has been loaded,
its methods can be invoked)
java::call mytest.dynamic.Test1 call
CALLED
Note that when
-java
is passed to
TJC::command,
either a
-readyvar or
-readycmd argument pair must
also be passed. One or more classes generated from the Java class
declaration are loaded into the current class loader. Be aware that the
class loader can only load a given Java class once. Redefining or
unloading a class
is not supported. Also note that when a -readycmd or -readyvar
notification is done with a -java argument, the Java classes that were
loaded are passed in place of the cmd element.