NAME
B::JVM::Jasmin - Perl Backend module for generating JVM code via Jasmin Assembler
SYNOPSIS
use B::JVM::Jasmin;
compile(KEEP_INTERMEDIATE_FILES_FLAG, [MAIN_CLASS_NAME]);
OR
perl -MO=JVM::Jasmin,KEEP_INTERMEDIATE_FILES_FLAG, [MAIN_CLASS_NAME] file.plx
DESCRIPTION
The B::JVM::Jasmin module is a Perl backend module that generates Jasmin assembler code (which can then be compiled into JVM code with jasmin(1)) for a Perl program.
AUTHOR
Bradley M. Kuhn, bkuhn@ebb.org, http://www.ebb.org/bkuhn
COPYRIGHT
Copyright (C) 1999, Bradley M. Kuhn, All Rights Reserved.
LICENSE
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the LICENSE file that was shipped with this distribution.
SEE ALSO
perl(1), jasmin(1).
DETAILED DOCUMENTATION
B::JVM::Jasmin Package Variables
- $VERSION
-
Version number of B::JVM::Jasmin
- @ISA
-
Canonical @ISA array, currently only derives from Exporter
- @EXPORT
-
Canonical @EXPORT array
- @EXPORT_OK
-
Canonical @EXPORT_OK array
- $STATE
-
Reference to a B::JVM::Jasmin::CompileState object for the current state of this compiler
Modules used by B::JVM::Jasmin
- B
-
Of course, we must use the B module to overide its functions and interface with O.
Methods in B::JVM::Jasmin
- B::JVM::Jasmin::compile
-
usage: B::JVM::Jasmin::compile(KEEP_INTERMEDIATE_FILES_FLAG, [MAIN_CLASS_NAME])
This is the default method that O.pm will call when this backend is used. The first argument is a flag that indicates whether or not to keep the intermediate temporary files that are generated by the compilation process. The second argument
- B::JVM::Jasmin::WalkOPTree
-
usage: B::JVM::Jasmin::compile($op, $level)
This method walks the op-tree and does pre and post processing on the op codes. In some cases, the pre-processing will call WalkOPTree for any sub-ops that exist.
- B::OP::JVMJasminPre
-
This method handles pre-processing on plain OPs. Note that for all these OPs, there are no recursive calls to WalkOPTree, since plain OPs should never have sub-OPs (I think :).
The following OPs are currently supported:
- enter
-
Currently, nothing is done on an "enter" OP. This may change in the future, but I haven't seen a use for them (yet :).
- pushmark
-
On an "pushmark" OP, the LIST_MARK is pushed onto the JVM operand stack. This indicates to other OPs that expect a list that the list ends here.
- null
-
A empty operation. Just send a "nop".
- B::OP::JVMJasminPost
-
Currently, there is no post processing done on plain OPs.
- B::LISTOP::JVMJasminPre
-
Pre-processing on LISTOPs requires that any we recursively call
WalkOPTree
, since LISTOPs can have children.The following LISTOPs are currently supported:
- leave
-
A "leave" LISTOP will be the parent of a number of OPs. Therefore, we process all the sub-OPs in order on the pre-processing step.
-
For a "print" LISTOP, we need to process the kids in reverse order, save pushing the
LIST_MARK
, which must happen first (the "print" post-processing depends on the mark being there). As in many instances, Perl appears to its own stack like a queue at times, and this causes problems, since we are using the JVM operand stack. In other words, for a "print" LISTOP, the Perl stack looks like this (left is top):LIST_MARK, "1", "2\n"
However, this would print the string "12\n", not "2\n1". It's as if Perl first finds the mark, and then processes from the mark to the end of the stack as a queue! (This behavior is probably documented somewhere else, but I just discovered it serendipitously (perhaps I should read documentation more :)). So, to process a "print" statement, we grab the "pushmark" OP first, process that, and then call
WalkOPTree
recursively in reverse for the rest of the sub-OPs. - list
-
On a "list" LISTOP, there is no need to "pushmark" (I think :). When the "list" LISTOP completes (at least from analyzing perl -Dts output) the mark simply disappears. It doesn't appear to be there for any other operation but the "list" LISTOP itself. If this isn't correct, this code will need to be corrected.
In addition, the list is reversed on the JVM operand stack, just as is done with the "print" LISTOP.
No post-processing is needed (I think :), because the "list" LISTOP just sets up arguments for another OP.
- scope
-
A "scope" LISTOP will be the parent of a number of OPs. Therefore, we process all the sub-OPs in order on the pre-processing step. May processing may be needed, but I haven't discovered that it is yet.
- B::LISTOP::JVMJasminPost
-
Post-processing on LISTOPs is often required, since the sub-OPs often set up arguments for processing.
The following LISTOPs currently have post-processing done:
-
At this point, the pre-processing should have set up the arguments to "print" on the JVM operand stack. A
LIST_MARK
should mark the end of the argument list on the JVM operand stack. A temporary variable is used to store the return value of the print statement. It is and'ed with eachFunctions.print
call return.At the end, we build a
StackElement
containing aScalar
that represents the final integer return value of the print statement.
- B::COP::JVMJasminPre
-
The following COPs are currently supported:
- nextstate
-
The "nextstate" COP clears the JVM operand stack. It finds the
STATE_MARK
, which indicates where and remaining data ends.The
STATE_MARK
is left on the stack.
- B::COP::JVMJasminPost
- B::SVOP::JVMJasminPre
-
The following SVOPs are currently supported:
- const
-
On a "const" SVOP, a
Scalar
and aStackElement
to hold it must be built. This is done by grabbing thecstring()
of the PV associated with the SV we are given. I don't know if every SV supports the PV() method, my thought is that it doesn't and this will need to be rewritten to handle other types of SVs.All this is done in pre-processing, no post-processing is necessary; the
StackElement
need only be left on the stack for whatever OP needs it.
- B::SVOP::JVMJasminPost
-
No post-processing is currently required for SVOPs.
- B::BINOP::JVMJasminPre
-
Pre-processing on BINOPs requires that any we recursively call
WalkOPTree
, for the two sub-opsThe following BINOPs are currently supported:
- sassign
-
To pre-process an "sassign" BINOP, we need only process the two sub-OPs. We do so in, so that in post-processing, we can assume that the left-hand-side of the assignment is first on the stack, and the right-hand-side is the second down element on the stack.
The post-processing actually does the assignment.
- concat
-
To pre-process a "concat" BINOP, we need only process the two sub-OPs. We do so in order. Post processing would be easier if it was done in reverse order (since the top of the JVM operand stack would be the result we need to keep), but it is imperative we go in order for cascading operations to have the proper semantics.
- seq and sne
-
To pre-process a "seq" and "sne" BINOPs, we need to process the two sub-OPs. We do so in order. Post processing would be easier if it was done in reverse order (since the top of the JVM operand stack would be the result we need to keep), but it is imperative we go in order for cascading operations to have the proper semantics.
- B::BINOP::JVMJasminPost
-
Currently, post-processing occurs on the following BINOPs:
- sassign
-
On post-processing, the "sassign" BINOP expects there to be two
StackElement
s on the JVM operand stack. The top is the left-hand-side of the "sassign", and below that (on the operand stack) is the right-hand-side of the "sassign". BothScalar
quantities will be wrapped inStackElements
.So, both
StackElement
s are converted intoScalar
. To do this, the functionTurnStackElementsToScalars
is called, and told to leave the stack elements in an array. The array that is returned is used set up theScalar
s for assignment.Then, to to perform the actual assignment,
assignFromScalar
is used.Finally, note as well that the left-hand-side
StackElement
is saved, as this should be the "return value" of the "sassign". It is left on the JVM operand stack at the end. - concat
-
On post-processing, the "concat" BINOP expects there to be two
StackElement
s on the JVM operand stack. The top is the right-operand of the "concat", and below that (on the operand stack) is the left-operand of the "concat". BothScalar
quantities will be wrapped inStackElements
.So, both
StackElement
s are converted intoScalar
. To do this, the functionTurnStackElementsToScalars
is called, and is told to leave the stack elements in an array. The array that is returned is used set up theScalar
s for concatenation.Then, to perform the actual concatenation,
Scalar.concat
function is used.Finally, note as well that the left-operand
StackElement
is saved, as this should be the "return value" of the "concat". It is left on the JVM operand stack at the end. - seq and sne
-
On post-processing, the "seq" and "sne" BINOPs expect there to be two
StackElement
s on the JVM operand stack. The top is the right-operand of the "seq", and below that (on the operand stack) is the left-operand of the "seq". BothScalar
quantities will be wrapped inStackElements
.So, both
StackElement
s are converted intoScalar
. To do this, the functionTurnStackElementsToScalars
is called, and is told to leave the stack elements in an array. The array that is returned is used set up theScalar
s for comparison.Then, to perform the actual comparison,
Scalar.seq
function is used.Then, we use that return value to create a new
Scalar
, wrapped in aStackElement
, which is left on the stack at the end.
- B::UNOP::JVMJasminPre
-
Pre-processing on UNOPs requires that any we recursively call
WalkOPTree
, for the two sub-opsThe following UNOPs are currently supported:
- null
-
On "null" UNOPs, we simply process the sub-OP. More interesting stuff happens in the post-processing.
- B::UNOP::JVMJasminPost
-
Post-processing on UNOPs is required because some flags needed to be checked. The results of the UNOP's child may require manipulation based on these flags.
The following UNOPs currently require post-processing:
- null
-
On a "null" UNOP, we need to check to see if the OPf_MOD flag is on. If it is not, then we need to make a copy of the
Scalar
result (wrapped in aStackElement
on the stack. We canno inadvertently modify the l-value of a variable, so we make the copy.If OPf_MOD is on, we need an l-value on the stack anyway, so things can be left alone.
- B::GVOP::JVMJasminPre
-
The following GVOPs are currently supported:
- gvsv
-
To pre-process a "gvsv" GVOP, we must find the correct
Scalar
object.First, the
DEF_STASH
is put on the JVM operand stack. Then, if this is not a variable in "main" namespace, we use thatDEF_STASH
to find the properStash
(this part not yet working FIXME). Once the requiredStash
is found, the properGV
is obtained, using methods from theStash
class). TheScalar
is retrieved from thatGV
. TheScalar
is then wrapped in aStackElement
object.
- B::GVOP::JVMJasminPost
-
Post-processing is not currently required on any GVOPs.
- B::LOGOP::JVMJasminPre
-
Pre-processing on LOGOPs requires that any we recursively call
WalkOPTree
, for the 3 sub-OPs.The following LOGOPs are currently supported:
- cond_expr
-
For an "cond_expr" LOGOP, we should have exactly three sub-OPs. This is a basic "if-else" structure (I think :). The first sub-OP will be the condition, the second sub-OP will be the block that should be executed if the condition is false, and the third is the block that should be executed if the condition is true.
So, we process each OP, and surround it with the logic that is required to carry out the conditional.
- B::LOGOP::JVMJasminPost
-
Currently, post-processing occurs on the following LOGOPs:
- ClearOperandStackToStateMark
-
usage:
ClearOperandStackToStateMark($emitter, $curMethod, $leaveStateMark);
This subroutine emits the required code to clear the JVM operand stack until a
StackElement
which is a state mark is reached. It emits the code using the given$emitter
and to the method,$curMethod
.If
$leaveStateMark
is defined and true, then theSTATE_MARK
is left on the stack, otherwise theSTATE_MARK
is removed. - TurnStackElementsToScalars
-
usage:
TurnStackElementsToScalars($emitter, $curMethod, $count, $leaveArray);
This subroutine emits the required code to take
$count
StackElement
s off the stack and turn them back intoScalar
s.It is completely required, that this function be called only if the top
$count
elements on the JVM operand stack beStackElement
objects who have valid elements.To do this, an array of
Scalar
s is built. A loop runs, getting theScalar
elements from theStackElement
s on the stack.If
$leaveArray
is defined and true, then the variable name of the array is simply returned. The array variable returned as yet to be freed.If
$leaveArray
not defined or is false, then, another loop runs to push all theScalar
s back onto the stack in the same order. The array varable is not returned (an empty string is returned instead). The array variable will be freed in this case.