L1Translator
The L1Translator transliterates a sequence of level one instructions into one or more simple level two instructions, under the assumption that further optimization steps will be able to transform this code into something much more efficient – without altering the level one semantics.
Author
Mark van Gulik
Todd L Smith
Parameters
The L2Generator for which I'm producing an initial translation from L1.
The Interpreter that tripped the translation request.
The A_RawFunction which is the source of the chunk being created.
Types
Functions
Add an L2Instruction.
Create and add an L2Instruction with the given L2Operation and variable number of L2Operands.
Emit the specified variable-reading instruction, and an off-ramp to deal with the case that the variable is unassigned.
Associate the specified L2ReadBoxedOperand with the semantic slot having the given index and effective pc. Restrict the type based on the register-read's TypeRestriction.
Generate code to invoke a function in a register with arguments in registers. Also branch to the appropriate reification and return clauses depending on whether the returned value is guaranteed to satisfy the expectedType or not.
n,m - Send the message at index n in the compiledCode's literals. Pop the arguments for this message off the stack (the message itself knows how many to expect). The first argument was pushed first, and is the deepest on the stack. Use these arguments to look up the method dynamically. Before invoking the method, push nil onto the stack. Its presence will help distinguish continuations produced by the pushLabel instruction from their senders. When the call completes (if ever) by using an implicit return instruction, it will replace this nil with the result of the call.
n,m - Pop the top n items off the stack, and use them as outer variables in the construction of a function based on the compiledCode that's the literal at index m of the current compiledCode.
The extension nybblecode was encountered. Read another nybble and dispatch it as an extended instruction.
n - Push the value of the local variable (not an argument) indexed by n (index 1 is first argument).
n - Push the value of the local variable (not an argument) indexed by n (index 1 is first argument). If the variable itself is mutable, clear it now - nobody will know.
n - Push the value of the outer variable indexed by n in the current function.
n - Push the value of the outer variable indexed by n in the current function. If the variable itself is mutable, clear it at this time - nobody will know.
n - Make a tuple from n values popped from the stack. Push the tuple.
n - Push the argument (actual value) or local variable (the variable itself) indexed by n. Since this is known to be the last use (non-debugger) of the argument or local, void that slot of the current continuation.
n - Push the outer variable indexed by n in the current function. If the variable is mutable, clear it (no one will know). If the variable and function are both mutable, remove the variable from the function by voiding it.
n - Push the literal indexed by n in the current compiledCode.
n - Push the argument (actual value) or local variable (the variable itself) indexed by n.
n - Push the outer variable indexed by n in the current function.
n - Pop the stack and assign this value to the local variable (not an argument) indexed by n (index 1 is first argument).
n - Pop the stack and assign this value to the outer variable indexed by n in the current function.
Duplicate the element at the top of the stack. Make the element immutable since there are now at least two references.
n - Push the value of the variable that's literal number n in the current compiledCode.
n - Permute the top n stack elements as specified by a literal permutation tuple. For example, if A, B, and C have been pushed, in that order, a permute tuple of <2, 3, 1> indicates the stack should have A in the 2nd slot, B in the 3rd, and C in the 1st. It has the same effect as having pushed C, and A, and B, in that order.
Build a continuation which, when restarted, will be just like restarting the current continuation.
n - Pop the stack and assign this value to the variable that's the literal indexed by n in the current compiledCode.
Pop the stack, writing the value directly into the indicated local slot. This is how local constants become initialized.
Invoke a method with a supercall.
Given an L2WriteBoxedOperand, produce an L2ReadBoxedOperand of the same value, but with the current manifest's TypeRestriction applied.
Answer the register holding the latest assigned version of the specified continuation slot. The slots are the arguments, then the locals, then the stack entries. The slots are numbered starting at 1.
Generate code to create the current continuation, with a nil caller, then L2_RETURN_FROM_REIFICATION_HANDLER – so the calling frames will also get a chance to add their own nil-caller continuations to the current StackReifier. The execution machinery will then assemble the chain of continuations, connecting them to any already reified continuations in the interpreter.
Properties
The raw function to transliterate into level two code.
The current L2ValueManifest, which tracks which L2Synonyms hold which L2SemanticValues at the current code generation point.
The L2Generator for which I'm producing an initial translation.