Documentation
¶
Index ¶
- Constants
- Variables
- func CopyPackagesToSymbols(s *symbols.SymbolTable)
- func Format(opcodes []instruction) string
- func FormatInstruction(i instruction) string
- func GetPackage(name string) (*data.Package, bool)
- func GoRoutine(fName string, parentCtx *Context, args []interface{})
- func IsPackage(name string) bool
- type ByteCode
- func (b *ByteCode) Append(a *ByteCode)
- func (b *ByteCode) Call(s *symbols.SymbolTable) (interface{}, error)
- func (b *ByteCode) ClearLineNumbers()
- func (b *ByteCode) Declaration() *data.FunctionDeclaration
- func (b *ByteCode) Disasm(ranges ...int)
- func (b *ByteCode) Emit(opcode Opcode, operands ...interface{})
- func (b *ByteCode) EmitAt(address int, opcode Opcode, operands ...interface{})
- func (b *ByteCode) Instruction(address int) *instruction
- func (b *ByteCode) Mark() int
- func (b *ByteCode) Name() string
- func (b ByteCode) NeedsCoerce(kind *data.Type) bool
- func (b *ByteCode) Opcodes() []instruction
- func (b *ByteCode) Patch(start, deleteSize int, insert []instruction)
- func (b *ByteCode) Remove(address int)
- func (b *ByteCode) Run(s *symbols.SymbolTable) error
- func (b *ByteCode) Seal() *ByteCode
- func (b *ByteCode) SetAddress(mark int, address int) error
- func (b *ByteCode) SetAddressHere(mark int) error
- func (b *ByteCode) SetDeclaration(fd *data.FunctionDeclaration) *ByteCode
- func (b *ByteCode) SetName(name string) *ByteCode
- func (b *ByteCode) String() string
- type CallFrame
- type ConstantWrapper
- type Context
- func (c *Context) AppendSymbols(s *symbols.SymbolTable) *Context
- func (c *Context) EnableConsoleOutput(flag bool) *Context
- func (c *Context) FormatFrames(maxDepth int) string
- func (c *Context) GetLine() int
- func (c *Context) GetModuleName() string
- func (c *Context) GetName() string
- func (c *Context) GetOutput() string
- func (c *Context) GetSymbols() *symbols.SymbolTable
- func (c *Context) GetTokenizer() *tokenizer.Tokenizer
- func (c *Context) IsRunning() bool
- func (c *Context) Pop() (interface{}, error)
- func (c *Context) PrintThisStack(operation string)
- func (c *Context) Result() interface{}
- func (c *Context) Resume() error
- func (c *Context) Run() error
- func (c *Context) RunFromAddress(addr int) error
- func (c *Context) SetBreakOnReturn()
- func (c *Context) SetByteCode(b *ByteCode) *Context
- func (c *Context) SetDebug(b bool) *Context
- func (c *Context) SetFullSymbolScope(b bool) *Context
- func (c *Context) SetGlobal(name string, value interface{}) error
- func (c *Context) SetPC(pc int) *Context
- func (c *Context) SetSingleStep(b bool) *Context
- func (c *Context) SetStepOver(b bool) *Context
- func (c *Context) SetTokenizer(t *tokenizer.Tokenizer) *Context
- func (c *Context) SingleStep() bool
- func (c *Context) StepOver(b bool)
- func (c *Context) Tracing() bool
- type DispatchMap
- type Opcode
- type OpcodeHandler
- type OptimizerOperation
- type StackMarker
Constants ¶
const ( // Discards the catch set, which means all errors are caught. AllErrorsCatchSet = 0 // Set of errors that an ?optional is permitted to ignore. OptionalCatchSet = 1 )
const GrowStackBy = 50
GrowStackBy indicates the number of elements to add to the stack when it runs out of space.
Variables ¶
var InstructionsExecuted atomic.Int64
InstructionsExecuted counts the number of byte code instructions executed.
var MaxStackSize atomic.Int32
MaxStackSize records the largest stack size encountered during a stack push operation. This can be used to determine if the initial stack size is adequate.
var Optimizations = []optimization{ { Description: "Load followed by SetThis", Pattern: []instruction{ { Operation: Load, Operand: placeholder{Name: "name"}, }, { Operation: SetThis, Operand: nil, }, }, Replacement: []instruction{ { Operation: LoadThis, Operand: placeholder{Name: "name"}, }, }, }, { Description: "Collapse constant push and createandstore", Pattern: []instruction{ { Operation: Push, Operand: placeholder{Name: "value"}, }, { Operation: CreateAndStore, Operand: placeholder{Name: "name"}, }, }, Replacement: []instruction{ { Operation: CreateAndStore, Operand: []interface{}{ placeholder{Name: "name"}, placeholder{Name: "value"}, }, }, }, }, { Description: "Unnecessary stack marker for constant store", Pattern: []instruction{ { Operation: Push, Operand: NewStackMarker("let"), }, { Operation: Push, Operand: placeholder{Name: "constant"}, }, { Operation: CreateAndStore, Operand: placeholder{Name: "name"}, }, { Operation: DropToMarker, Operand: NewStackMarker("let"), }, }, Replacement: []instruction{ { Operation: Push, Operand: placeholder{Name: "constant"}, }, { Operation: CreateAndStore, Operand: placeholder{Name: "name"}, }, }, }, { Description: "Sequential PopScope", Pattern: []instruction{ { Operation: PopScope, Operand: placeholder{Name: "count1", Operation: OptCount, Register: 1}, }, { Operation: PopScope, Operand: placeholder{Name: "count2", Operation: OptCount, Register: 1}, }, }, Replacement: []instruction{ { Operation: PopScope, Operand: placeholder{Name: "count", Operation: OptRead, Register: 1}, }, }, }, { Description: "Create and store", Pattern: []instruction{ { Operation: SymbolCreate, Operand: placeholder{Name: "symbolName"}, }, { Operation: Store, Operand: placeholder{Name: "symbolName"}, }, }, Replacement: []instruction{ { Operation: CreateAndStore, Operand: placeholder{Name: "symbolName"}, }, }, }, { Description: "Push and Storeindex", Pattern: []instruction{ { Operation: Push, Operand: placeholder{Name: "value"}, }, { Operation: StoreIndex, }, }, Replacement: []instruction{ { Operation: StoreIndex, Operand: placeholder{Name: "value"}, }, }, }, { Description: "Constant storeAlways", Pattern: []instruction{ { Operation: Push, Operand: placeholder{Name: "value"}, }, { Operation: StoreAlways, Operand: placeholder{Name: "name"}, }, }, Replacement: []instruction{ { Operation: StoreAlways, Operand: []interface{}{ placeholder{Name: "name"}, placeholder{Name: "value"}, }, }, }, }, { Description: "Constant addition fold", Pattern: []instruction{ { Operation: Push, Operand: placeholder{Name: "v1"}, }, { Operation: Push, Operand: placeholder{Name: "v2"}, }, { Operation: Add, }, }, Replacement: []instruction{ { Operation: Push, Operand: placeholder{Name: "sum", Operation: OptRunConstantFragment}, }, }, }, { Description: "Constant subtraction fold", Pattern: []instruction{ { Operation: Push, Operand: placeholder{Name: "v1"}, }, { Operation: Push, Operand: placeholder{Name: "v2"}, }, { Operation: Sub, }, }, Replacement: []instruction{ { Operation: Push, Operand: placeholder{Name: "difference", Operation: OptRunConstantFragment}, }, }, }, { Description: "Constant multiplication fold", Pattern: []instruction{ { Operation: Push, Operand: placeholder{Name: "v1"}, }, { Operation: Push, Operand: placeholder{Name: "v2"}, }, { Operation: Mul, }, }, Replacement: []instruction{ { Operation: Push, Operand: placeholder{Name: "product", Operation: OptRunConstantFragment}, }, }, }, }
Functions ¶
func CopyPackagesToSymbols ¶
func CopyPackagesToSymbols(s *symbols.SymbolTable)
func FormatInstruction ¶
func FormatInstruction(i instruction) string
FormatInstruction formats a single instruction as a string.
Types ¶
type ByteCode ¶
type ByteCode struct {
// contains filtered or unexported fields
}
ByteCode contains the context of the execution of a bytecode stream. Note that there is a dependency in format.go on the name of the "Declaration" variable. PLEASE NOTE that Name must be exported because reflection is used to format opaque pointers to bytecodes in the low-level formatter.
func (*ByteCode) Append ¶
Append appends another bytecode set to the current bytecode, and updates all the branch references within that code to reflect the new base locaation for the code segment.
func (*ByteCode) Call ¶
func (b *ByteCode) Call(s *symbols.SymbolTable) (interface{}, error)
Call generates a one-time context for executing this bytecode, and returns a value as well as an error condition if there was one from executing the code.
func (*ByteCode) ClearLineNumbers ¶
func (b *ByteCode) ClearLineNumbers()
ClearLineNumbers scans the bytecode and removes the AtLine numbers in the code so far. This is done when the @line directive resets the line number; all previous line numbers are no longer valid and are set to zero.
func (*ByteCode) Declaration ¶
func (b *ByteCode) Declaration() *data.FunctionDeclaration
Return the declaration object from the bytecode. This is primarily used in routines that format information about the bytecode. If you change the name of this function, you will also need to update the MethodByName() calls for this same function name.
func (*ByteCode) Disasm ¶
Disasm prints out a representation of the bytecode for debugging purposes.
func (*ByteCode) Emit ¶
Emit emits a single instruction. The opcode is required, and can optionally be followed by an instruction operand (based on whichever instruction) is issued. The instruction is emitted at the current "next address" of the bytecode object, which is then incremented.
func (*ByteCode) EmitAt ¶
EmitAT emits a single instruction. The opcode is required, and can optionally be followed by an instruction operand (based on whichever instruction) is issued. This stores the instruction at the given location in the bytecode array, but does not affect the emit position unless this operation required expanding the bytecode storage.
func (*ByteCode) Instruction ¶
Instruction retrieves the instruction at the given address.
func (*ByteCode) Mark ¶
Mark returns the address of the next instruction to be emitted. Use this BERFORE a call to Emit() if using it for branch address fixups later.
func (*ByteCode) Opcodes ¶
func (b *ByteCode) Opcodes() []instruction
Opcodes returns the opcode list for this bytecode array.
func (*ByteCode) Remove ¶
Remove removes an instruction from the bytecode. The address is >= 0 it is the absolute address of the instruction to remove. Otherwise, it is the offset from the end of the bytecode to remove.
func (*ByteCode) Run ¶
func (b *ByteCode) Run(s *symbols.SymbolTable) error
Run generates a one-time context for executing this bytecode, and then executes the code.
func (*ByteCode) Seal ¶
Truncate the output array to the current bytecode size. This is also where we will optionally run an optimizer.
func (*ByteCode) SetAddress ¶
SetAddress sets the given value as the target of the marked instruction. This is often used when an address has been saved and we need to update a branch destination, usually for a backwards branch operation.
func (*ByteCode) SetAddressHere ¶
SetAddressHere sets the current address as the detination of the instruction at the marked location. This is used for address fixups, typically for forward branches.
func (*ByteCode) SetDeclaration ¶
func (b *ByteCode) SetDeclaration(fd *data.FunctionDeclaration) *ByteCode
type CallFrame ¶
type CallFrame struct { Module string Line int Package string // contains filtered or unexported fields }
CallFrame is an object used to store state of the bytecode runtime environment just before making a call to a bytecode subroutine. This preserves the state of the stack, PC, and other data at the time of the call. When a bytecode subroutine returns, this object is removed from the stack and used to reset the bytecode runtime state.
Note that this is exported (as are Module and Line within it) to support formatting of trace data using reflection.
type ConstantWrapper ¶
type ConstantWrapper struct {
Value interface{}
}
Note there are reflection dependencies on the name of the field; it must be named "Value".
func (ConstantWrapper) String ¶
func (w ConstantWrapper) String() string
String generates a human-readable string describing the value in the constant wrapper.
type Context ¶
type Context struct {
// contains filtered or unexported fields
}
Context holds the runtime information about an instance of bytecode being executed.
func NewContext ¶
func NewContext(s *symbols.SymbolTable, b *ByteCode) *Context
NewContext generates a new context. It must be passed a symbol table and a bytecode array. A context holds the runtime state of a given execution unit (program counter, runtime stack, symbol table) and is used to actually run bytecode. The bytecode can continue to be modified after it is associated with a context.
func (*Context) AppendSymbols ¶
func (c *Context) AppendSymbols(s *symbols.SymbolTable) *Context
AppendSymbols appends a symbol table to the current context. This is used to add in compiler maps, for example.
func (*Context) EnableConsoleOutput ¶
EnableConsoleOutput tells the context to begin capturing all output normally generated from Print and Newline into a buffer instead of going to stdout.
func (*Context) FormatFrames ¶
FormatFrames is called from the runtime debugger to print out the current call frames stored on the stack. It chases the stack using the frame pointer (FP) in the current context which points to the saved frame. Its FP points to the previous saved frame, and so on.
func (*Context) GetLine ¶
GetLine retrieves the current line number from the original source being executed. This is stored in the context every time an AtLine instruction is executed.
func (*Context) GetModuleName ¶
GetModuleName returns the name of the current module (typically the function name or program name).
func (*Context) GetOutput ¶
GetOutput retrieves the output buffer. This is the buffer that contains all Print and related bytecode instruction output. This is used when output capture is enabled, which typically happens when a program is running as a Web service.
func (*Context) GetSymbols ¶
func (c *Context) GetSymbols() *symbols.SymbolTable
func (*Context) GetTokenizer ¶
GetTokenizer gets the tokenizer in the current context for tracing and debugging.
func (*Context) PrintThisStack ¶
Add a line to the trace output that shows the "this" stack of saved function receivers.
func (*Context) RunFromAddress ¶
RunFromAddress executes a bytecode context from a given starting address.
func (*Context) SetBreakOnReturn ¶
func (c *Context) SetBreakOnReturn()
func (*Context) SetByteCode ¶
SetByteCode attaches a new bytecode object to the current run context.
func (*Context) SetFullSymbolScope ¶
SetFullSymbolScope sets the flag that indicates if a symbol table read can "see" a symbol outside the current function. The default is off, which means symbols are not visible outside the function unless they are in the global symbol table. If true, then a symbol can be read from any level of the symbol table parentage chain.
func (*Context) SetGlobal ¶
SetGlobal stores a value in a the global symbol table that is at the top of the symbol table chain.
func (*Context) SetPC ¶
SetPC sets the program counter (PC) which indicates the next instruction number to execute.
func (*Context) SetSingleStep ¶
SetSingleStep enables or disables single-step mode. This has no effect if debugging is not active.
func (*Context) SetStepOver ¶
SetStepOver determines if single step operations step over a function call, or step into it.
func (*Context) SetTokenizer ¶
SetTokenizer sets a tokenizer in the current context for use by tracing and debugging operations. This gives those functions access to the token stream used to compile the bytecode in this context.
func (*Context) SingleStep ¶
SingleStep retrieves the current single-step setting for this context. This is used in the debugger to know how to handle break operations.
type DispatchMap ¶
type DispatchMap map[Opcode]OpcodeHandler
DispatchMap is a map that is used to locate the function for an opcode.
type Opcode ¶
type Opcode int
Constant describing instruction opcodes.
const ( Stop Opcode = iota // Stop must be the zero-th item. AtLine Add AddressOf And ArgCheck Array Auth BitAnd BitOr BitShift Call Coerce Constant Copy CreateAndStore DeRef Div Drop DropToMarker Dup EntryPoint Equal Exp Explode Flatten FromFile GetThis GetVarArgs Go GreaterThan GreaterThanOrEqual Import InFile InPackage LessThan LessThanOrEqual Load LoadIndex LoadSlice LoadThis Log MakeArray MakeMap Member ModeCheck Modulo Mul Negate Newline NoOperation NotEqual Or Panic PopPackage PopScope Print Push PushPackage PushScope RangeInit ReadStack RequiredType Response Return Say SetThis StackCheck StaticTyping Store StoreAlways StoreBytecode StoreChan StoreGlobal StoreIndex StoreInto StoreViaPointer Struct Sub Swap SymbolCreate SymbolDelete SymbolOptCreate Template Timer TryPop Wait WillCatch // Everything from here on is a branch instruction, whose // operand must be present and is an integer instruction // address in the bytecode array. These instructions are // patched with offsets when code is appended. // // The first one in this list MIUST be BranchInstructions, // as it marks the start of the branch instructions, which // are instructions that can reference a bytecode address // as the operand. BranchInstructions Branch BranchTrue BranchFalse LocalCall RangeNext Try )
type OpcodeHandler ¶
OpcodeHandler defines a function that implements an opcode.
type OptimizerOperation ¶
type OptimizerOperation int
const ( OptNothing OptimizerOperation = iota OptStore OptRead OptCount OptRunConstantFragment )
type StackMarker ¶
type StackMarker struct {
// contains filtered or unexported fields
}
StackMarker is a special object used to mark a location on the stack. It is used, for example, to mark locations to where a stack should be flushed. The marker contains a text description, and optionally any additional desired data.
func NewStackMarker ¶
func NewStackMarker(label string, values ...interface{}) StackMarker
NewStackMarker generates a enw stack marker object, using the supplied label and optional list of datu.
func (StackMarker) String ¶
func (sm StackMarker) String() string
Produce a string reprsentation of a stack marker.