Package-level declarations
Types
Add the value in one int register to another int register, jumping to the specified target if the result does not fit in an int.
Box a double into an AvailObject.
Box an Int into an AvailObject.
Clear a variable; i.e., make it have no assigned value.
Concatenate the tuples in the vector of object registers to produce a single tuple in an output register.
Create a continuation from scratch, using the specified caller, function, constant level one program counter, constant stack pointer, continuation slot values, and level two program counter. Write the new continuation into the specified register.
Synthesize a new function from the provided constant compiled code and the vector of captured ("outer") variables.
Create a map from the specified key object registers and the corresponding value object registers (writing the map into a specified object register).
Create an object using a constant pojo holding an ObjectLayoutVariant and a vector of values, in the order the variant lays them out as fields.
Create a set from the values in the specified vector of object registers.
Create a fixed sized tuple type from the types in the specified registers.
Create a new variable object of the specified variable type.
Explicitly decrement the current compiled code's countdown via A_RawFunction.countdownToReoptimize. If it reaches zero then re-optimize the code and jump to its L2Chunk.offsetAfterInitialTryPrimitive, which expects the arguments to still be set up in the Interpreter.
If the divisor is zero, then jump to the zero divisor label. Otherwise divide the dividend int by the divisor int. If the quotient and remainder each fit in an Int, then store them and continue, otherwise jump to an out-of-range label.
Divide the dividend value by the divisor value. If the calculation causes an ArithmeticException, jump to the specified label, otherwise set the quotient and remainder registers and continue with the next instruction.
This marks the entry point into optimized (level two) code. At entry, the arguments are expected to be in the Interpreter.argsBuffer. Set up fresh registers for this chunk, but do not write to them yet.
Extract the A_Function from an A_Continuation.
Extract a single slot from a continuation.
Extract the ObjectLayoutVariant of the given object type, then extract its variantId as an Int.
Extract the ObjectLayoutVariant of the given object, then extract its variantId as an Int.
Convert a double to an Int.
Given an input register containing a function (not a function type), extract its Nth parameter type.
Ask the Interpreter for its Interpreter.argsBuffer's n-th element.
Ask the Interpreter for the current continuation, writing it into the provided register. Note that this continuation is just the Interpreter.getReifiedContinuation field, so it may represent the current function, its caller, or just the top reified continuation with many layers unreified within the Java stack.
Ask the Interpreter for the current function, writing it into the provided register.
Store the implicit observe function into the supplied object register.
Store the invalid message send function into the supplied object register.
Ask the Interpreter for its Interpreter.getLatestResult, which is how functions return values.
Extract the specified field of the object.
Extract the specified field type of the given object type.
Given a phrase, extract its expression type.
Ask the Interpreter for the current function, writing it into the provided register.
Extract the exact type of an object in a register, writing the type to another register.
Store the current A_Function from the HookType.READ_UNASSIGNED_VARIABLE into the supplied object register.
Extract the value of a variable. If the variable is unassigned, then branch to the specified offset.
Extract the value of a variable, while simultaneously clearing it. If the variable is unassigned, then branch to the specified offset.
Answer the hash of the specified value.
Extract the sole instance, itself a type, of the specified metatype.
Convert an int to a double.
Use the Interpreter.levelOneStepper to execute Level One unoptimized nybblecodes. If an interrupt request is indicated, or if a call anywhere within this code arranges to reify the fiber, return a StackReifier, making sure to synthesize a continuation for the current frame.
The given function is invoked. The function may be a primitive, and the primitive may succeed, fail, or replace the current continuation (after reifying the stack). It may also trigger reification of this frame by Java-returning a StackReifier instead of null.
The given (constant) function is invoked. The function may be a primitive, and the primitive may succeed, fail, or replace the current continuation (after reifying the stack). It may also trigger reification of this frame by Java-returning a StackReifier instead of null.
Invoke the AvailRuntime.resultDisagreedWithExpectedTypeFunction handler function, via Interpreter.reportWrongReturnType, which takes responsibility for assembling an A_Continuation in the event of reification.
Invoke the AvailRuntime.unassignedVariableReadFunction handler function, via Interpreter.reportUnassignedVariableRead, which takes responsibility for assembling an A_Continuation in the event of reification.
Unconditionally jump to the level two offset in my only operand.
Unconditionally jump to the level two offset in my L2PcOperand, while also limiting that edge's L2ValueManifest to the L2ReadVectorOperand's reads.
Reification of the stack into a chain of A_Continuations is powerful, and provides backtracking, exceptions, readable stack traces, and reliable debugger support. However, it's also expensive.
Jump to the target if int1 compares to int2 in the way requested by the opcode.
Jump to "if equal" if the value equals the constant, otherwise jump to "if unequal".
Jump to the target if the object is numerically greater than the constant.
Jump to the target if the first value is numerically greater than the second value.
Jump to the target if the object is numerically greater than or equal to the constant.
Jump to the target if the first value is numerically greater than or equal to the second value.
Jump to the specified level two program counter if no interrupt has been requested since last serviced. Otherwise an interrupt has been requested and we should proceed to the next instruction.
Jump to the target if the object is an instance of the constant type.
Jump to the target if the value is an instance of the type.
Jump to the target if the object is numerically less than the constant.
Jump to the target if the first value is numerically less than the second value.
Jump to the target if the object is numerically less than or equal to the constant.
Jump to the target if the first value is numerically less than or equal to the second value.
Branch based on whether the two values are equal to each other.
Conditionally jump, depending on whether the type to check is a subtype of the constant type.
Conditionally jump, depending on whether the first type is a subtype of the second type.
Jump to "if unboxed" if a double was unboxed from an AvailObject, otherwise jump to "if not unboxed".
Jump to "if unboxed" if an Int was unboxed from an AvailObject, otherwise jump to "if not unboxed".
Look up the method to invoke. Use the provided vector of argument types to perform a polymorphic lookup. Write the resulting function into the specified destination register. If the lookup fails, then branch to the specified offset.
Look up the method to invoke. Use the provided vector of arguments to perform a polymorphic lookup. Write the resulting function into the specified destination register. If the lookup fails, then branch to the specified offset.
Force the specified object to be immutable. Maintenance of conservative sticky-bit reference counts is mostly separated out into this operation to allow code transformations to obviate the need for it in certain non-obvious circumstances.
Move an AvailObject from the source to the destination. The L2Generator creates more moves than are strictly necessary, but various mechanisms cooperate to remove redundant inter-register moves.
Move a constant AvailObject into a register. Instances of this operation are customized for different RegisterKinds.
Extract a captured "outer" variable from a function. If the outer variable is an actual variable then the variable itself is what gets moved into the destination register.
Multiply the value in one int register by the value in another int register, storing back in the second if the result fits in an int without overflow. Otherwise jump to the specified target.
Given an integer and a constant tuple of N distinct integers in ascending order, determine where the provided integer fits between the integers in the tuple. Then jump to one of the N+1 targets based on that computed index.
The L2_PHI_PSEUDO_OPERATION occurs at the start of a L2BasicBlock. It's a convenient fiction that allows an L2ControlFlowGraph to be in Static Single Assignment form (SSA), where each L2Register has exactly one instruction that writes to it.
This operation is only used when entering a function that uses the default chunk. A new function has been set up for execution. Its arguments have been written to the architectural registers. If this is a primitive, then the primitive has already been attempted and failed, writing the failure value into the failureValueRegister(). Set up the pc and stackp, as well as local variables. Also transfer the primitive failure value into the first local variable if this is a primitive (and therefore failed).
This is the first instruction of the L1 interpreter's on-ramp for resuming after a callee returns. The reified A_Continuation that was captured (and is now being resumed) pointed to this L2Instruction. That continuation is current in the Interpreter.getReifiedContinuation. Pop it from that continuation chain, create suitable pointer and integer registers as expected by L2_INTERPRET_LEVEL_ONE, then explode the continuation's slots into those registers. The Interpreter.function should also have already been set up to agree with the continuation's function.
This is the first instruction of the L1 interpreter's on-ramp for resuming after an interrupt. The reified A_Continuation that was captured (and is now being resumed) pointed to this L2Instruction. That continuation is current in the Interpreter.getReifiedContinuation. Pop it from that continuation chain, create suitable pointer and integer registers as expected by L2_INTERPRET_LEVEL_ONE, then explode the continuation's slots into those registers. The Interpreter.function should also have already been set up to agree with the continuation's function.
Create a StackReifier and jump to the "on reification" label. This will reify the entire Java stack (or discard it if "capture frames" is false). If "process interrupt" is true, then process an interrupt as soon as the reification is complete. Otherwise continue running at "on reification" with the reified state captured in the Interpreter.getReifiedContinuation.
Restart the given continuation, which already has the correct program counter and level two offset (in case the L2Chunk is still valid). The function will start at the beginning, using the same arguments that were captured within the continuation.
Restart the given continuation, which already has the correct program counter and level two offset (in case the L2Chunk is still valid). The function will start at the beginning, using the supplied arguments, rather than the ones that were captured within the continuation.
Return from the current L2Chunk with the given return value. The value to return will be stored in Interpreter.setLatestResult, so the caller will need to look there.
Return from the reification clause of the current L2Chunk. This clause was invoked when a request for reification was detected inside an invocation instruction. The operand supplies a sequence of continuations (each with nil callers), in the order in which the corresponding non-inlined versions of the functions would have been invoked.
Execute a primitive with the provided arguments, writing the result into the specified register. The primitive must not fail. Don't check the result type, since the VM has already guaranteed it is correct.
Extract the given "reference" edge's target level two offset as an Int, then follow the fall-through edge. The int value will be used in the fall-through code to assemble a continuation, which, when returned into, will start at the reference edge target. Note that the L2 offset of the reference edge is not known until just before JVM code generation.
Set the Interpreter.setReifiedContinuation.
Assign a value to a variable.
Assign a value to a variable without checking that it's of the correct type.
Grant the specified input object a stronger type. This instruction must survive a L2Regenerator, so it's treated as having a side-effect, even though it generates no JVM instructions. In general, an L2Operation has the responsibility to propagate type information when the containing L2Instruction is emitted, but sometimes that isn't convenient, such as when some property p(f(x)) is shown to hold, implying x itself should be consequently constrained to have some other property p'(x).
This is a helper operation which produces no JVM code, but is useful to limit which L2Registers and L2SemanticValues are live when reaching a back-edge.
Subtract the subtrahend from the minuend, jumping to the specified target if the result does not fit in an int.
Expect the AvailObject (pointers) array and int array to still reflect the caller. Expect Interpreter.argsBuffer to have been loaded with the arguments to this possible primitive function, and expect the code/function/chunk to have been updated for this primitive function. Try to execute a potential primitive, setting the Interpreter.returnNow flag and latestResult if successful. The caller always has the responsibility of checking the return value, if applicable at that call site. Used only by the unoptimizedChunk.
Expect the AvailObject (pointers) array and int array to still reflect the caller. Expect Interpreter.argsBuffer to have been loaded with the arguments to this primitive function, and expect the code/function/chunk to have been updated for this primitive function. Try to execute a primitive, setting the Interpreter.returnNow flag and latestResult if successful. The caller always has the responsibility of checking the return value, if applicable at that call site.
Extract an element at a fixed subscript from a tuple that is known to be long enough, writing the element into a register.
Extract an element at a subscript from a tuple that is known to be within bounds, writing the element into a register.
Given a tuple, an immediate index, and a new value to write, create the tuple with that element replaced by the new value. Destroy or recycle the original if it's mutable. Write the output to the specified output register.
Given two input types in registers, compute their union and write it to the output register.
Unbox an float from an AvailObject.
Unbox an Int from an AvailObject.
This instruction should never be reached. Stop the VM if it is. We need the instruction for dealing with labels that should never be jumped to, but still need to be provided for symmetry reasons.
This is a placeholder instruction, which is replaced if still live after data flow optimizations by:
Jump to "if satisfied" if some condition is met, otherwise jump to "if unsatisfied".
An L2Operation that alters control flow, and therefore does not fall through to the next instruction.